sandbox/farsoiya/marangoni_surfactant/marangoni.h
Surface derivative calculation of surface tension coefficient Seric. et. al. 2018
attribute {
vector chi;
}
scalar sigmaf[];
vector iforce[];
bool addmarangoni = 1;
#include "iforce.h"
#include "curvature.h"
event stability (i++)
{We first compute the minimum and maximum values of \alpha/f_m = 1/\rho, as well as \Delta_{min}.
double amin = HUGE, amax = -HUGE, dmin = HUGE;
foreach_face (reduction(min:amin) reduction(max:amax) reduction(min:dmin))
if (fm.x[] > 0.) {
if (alpha.x[]/fm.x[] > amax) amax = alpha.x[]/fm.x[];
if (alpha.x[]/fm.x[] < amin) amin = alpha.x[]/fm.x[];
if (Delta < dmin) dmin = Delta;
}
double rhom = (1./amin + 1./amax)/2.;The maximum timestep is set using the sum of surface tension coefficients.
//~ double sigma = 0.;
for (scalar c in interfaces)
//~ sigma += c.sigma;
foreach(serial){
if (sigmaf[] > 0) {
double dt = sqrt (rhom*cube(dmin)/(pi*sigmaf[]));
if (dt < dtmax)
dtmax = dt;
}
if (addmarangoni == 1){
foreach_dimension()
if (fabs(iforce.x[]) > 1.e-6) {
rhom = fmin(rho1,rho2);
double dt = 2.*dmin/(fabs(u.x[]) + sqrt(sq(u.x[]) + 4.*fabs(iforce.x[])/rhom )); //sqrt (rhom*sq(dmin)/(iforce.x[]));
if (dt < dtmax)
dtmax = dt;
}
}
}
}
static inline bool interf (double c)
{
if (c > 1.e-6 && c < 1. - 1.e-6)
return true;
else
return false;
}
#if dimension == 2
foreach_dimension()
static double marangoni_y (Point point, vector h, coord * dsigt)
{
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;
double sigmaleft = 0., fsumleft = 0., sigmaright = 0., fsumright = 0., sigmacenter = 0., fsumcenter = 0.;
//I get mean value of sigma on 3 cells in a column (y-direction)
for (int i = -1; i <= 1; i++){
// printf("\n%d\t%g", i, f[-1,i]); fflush(stdout);
//PALAS: CHECK HOW THIS WORKS IN X-ORIENTATION
if (interf(f[-1,i])){
sigmaleft += f[-1,i]*sigmaf[-1,i];
fsumleft += f[-1,i];
}
if (interf(f[0,i])){
sigmacenter += f[0,i]*sigmaf[0,i];
fsumcenter += f[0,i];
}
if (interf(f[1,i])){
sigmaright += f[1,i]*sigmaf[1,i];
fsumright += f[1,i];
}
}
double ds = 0., dsigmadx = 0.;
if (fsumleft >= 1.e-6 && fsumright >= 1.e-6){
sigmaleft = sigmaleft/fsumleft; //mean of multiple cells in column
sigmaright = sigmaright/fsumright; //mean of multiple cells in column
ds = 2.*Delta*pow(1. + (hx*hx), 0.5); // length of h
dsigmadx = (sigmaright - sigmaleft)/ds;
}
else if (fsumleft < 1.e-6 && fsumright > 1.e-6 && fsumcenter > 1.e-6){
sigmacenter = sigmacenter/fsumcenter; //mean of multiple cells in column
sigmaright = sigmaright/fsumright; //mean of multiple cells in column
ds = Delta*pow(1. + (hx*hx), 0.5); // length of h
dsigmadx = (sigmaright - sigmacenter)/ds;
}
else if (fsumleft > 1.e-6 && fsumright < 1.e-6 && fsumcenter > 1.e-6){
sigmaleft = sigmaleft/fsumleft; //mean of multiple cells in column
sigmacenter = sigmacenter/fsumcenter; //mean of multiple cells in column
ds = Delta*pow(1. + (hx*hx), 0.5); // length of h
dsigmadx = (sigmacenter - sigmaleft)/ds;
}
else {
dsigmadx = 0.;
// Fix thses errors to find bugs
// printf("\nError in calculating dsigmadx\n");
// dump("error_file");
// exit(0);
}
//printf("\n ds = %g",ds);
//exit(0);
coord signtangent;
signtangent.x = 1;
signtangent.y = 1;
coord n;
n.x = dsigt->x; n.y = dsigt->y; // get normal values passed using dsigt
//1st quad normal, tangent dir is in increasing x direction (tripathi et. al.)
if ( (n.x > 0. && n.y > 0.) ){
//tangent is 4th quad
signtangent.x = 1.;
signtangent.y = -1.;
}
//2nd quad
if ( (n.x < 0. && n.y > 0.) ){
//tangent is in 1st quad
signtangent.x = 1.;
signtangent.y = 1.;
}
//3rd quad
if ( (n.x < 0. && n.y < 0.) ){
//tangent is in 4th quad
signtangent.x = 1.;
signtangent.y = -1.;
}
//4th quad
if ( (n.x > 0. && n.y < 0.) ){
//tangent is in 1st quad
signtangent.x = 1.;
signtangent.y = 1.;
}
dsigt->x = signtangent.x * dsigmadx / pow(1. + (hx*hx), 0.5 ); //unity component of tangent vector
dsigt->y = signtangent.y * dsigmadx * fabs(hx)/pow(1. + (hx*hx), 0.5);
return hxx/pow(1. + sq(hx), 3/2.);
}
#else // dimension == 3
foreach_dimension()
static double marangoni_z (Point point, vector h, coord * dsigt)
{
bool hf_failed_for_curvature = 0;
int ori = orientation(h.z[]);
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
if (h.z[i,j] == nodata || orientation(h.z[i,j]) != ori)
hf_failed_for_curvature = 1;
double hx = (h.z[1] - h.z[-1])/2.;
double hy = (h.z[0,1] - h.z[0,-1])/2.;
double fl1,fl2,fl3;
double fr1,fr2,fr3;
double fc1, fc2, fc3;
double sl1,sl0,slm1;
double sr1,sr0,srm1;
double hl = 0., hc = 0., hr = 0., hyl = 0., hyc =0. , hyr = 0.;
fl1 = f[-1,0,-1]; fl2 = f[-1,0,0]; fl3 = f[-1,0,1];
fc1 = f[0,0,-1]; fc2 = f[0,0,0]; fc3 = f[0,0,1];
fr1 = f[1,0,-1]; fr2 = f[1,0,0]; fr3 = f[1,0,1];
//We check whether the four heights on the x-y stencil are available to find the
//tangent of the interface in both directions
if (h.z[1] == nodata || h.z[-1] == nodata || orientation(h.z[1]) != ori || orientation(h.z[-1]) != ori){
for (int i = -2; i <= 2; i++){
hl += f[-1,0,i];
hr += f[1,0,i];
}
hx = (hr - hl)/2.;
}
if (h.z[0,-1] == nodata || h.z[0,1] == nodata || orientation(h.z[0,1]) != ori || orientation(h.z[0,-1]) != ori)
{
for (int i = -2; i <= 2; i++){
hyl += f[0,-1,i];
hyr += f[0,1,i];
}
hy = (hyr - hyl)/2.;
}We “filter” the curvature using a weighted sum of the three second-derivatives in the x and y directions. This is necessary to avoid a numerical mode when the curvature is used to compute surface tension.
double filter = 0.2;
double hxx = (filter*(h.z[1,1] + h.z[-1,1] - 2.*h.z[0,1]) +
(h.z[1] + h.z[-1] - 2.*h.z[]) +
filter*(h.z[1,-1] + h.z[-1,-1] - 2.*h.z[0,-1]))/
((1. + 2.*filter)*Delta);
double hyy = (filter*(h.z[1,1] + h.z[1,-1] - 2.*h.z[1]) +
(h.z[0,1] + h.z[0,-1] - 2.*h.z[]) +
filter*(h.z[-1,1] + h.z[-1,-1] - 2.*h.z[-1]))/
((1. + 2.*filter)*Delta);
double hxy = (h.z[1,1] + h.z[-1,-1] - h.z[1,-1] - h.z[-1,1])/(4.*Delta);
double sigmaleft = 0., fsumleft = 0., sigmaright = 0., fsumright = 0., sigmacenter = 0., fsumcenter = 0.;
//I get mean value of sigma on 3 cells in a column (y-direction)
for (int i = -2; i <= 2; i++){
// printf("\n%d\t%g", i, f[-1,i]); fflush(stdout);
//Calculate derivative in X-Z plane
if (interf(f[-1,0,i])){
sigmaleft += f[-1,0,i]*sigmaf[-1,0,i];
fsumleft += f[-1,0,i];
}
if (interf(f[0,0,i])){
sigmacenter += f[0,0,i]*sigmaf[0,0,i];
fsumcenter += f[0,0,i];
}
if (interf(f[1,0,i])){
sigmaright += f[1,0,i]*sigmaf[1,0,i];
fsumright += f[1,0,i];
}
}
// sl1 = sigmaf[-1,-1]; sl0 = sigmaf[-1,0]; slm1 = sigmaf[-1,-1];
// sr1 = sigmaf[1,-1]; sr0 = sigmaf[1,0]; srm1 = sigmaf[1,-1];
double dsx = 0., dsigmadx = 0.;
if (fsumleft >= 1.e-6 && fsumright >= 1.e-6){
sigmaleft = sigmaleft/fsumleft; //mean of multiple cells in column
sigmaright = sigmaright/fsumright; //mean of multiple cells in column
dsx = 2.*Delta*pow(1. + (hx*hx), 0.5); // length of h
dsigmadx = (sigmaright - sigmaleft)/dsx;
}
else if (fsumleft < 1.e-6 && fsumright > 1.e-6 && fsumcenter > 1.e-6){
sigmacenter = sigmacenter/fsumcenter; //mean of multiple cells in column
sigmaright = sigmaright/fsumright; //mean of multiple cells in column
dsx = Delta*pow(1. + (hx*hx), 0.5); // length of h
dsigmadx = (sigmaright - sigmacenter)/dsx;
}
else if (fsumleft > 1.e-6 && fsumright < 1.e-6 && fsumcenter > 1.e-6){
sigmaleft = sigmaleft/fsumleft; //mean of multiple cells in column
sigmacenter = sigmacenter/fsumcenter; //mean of multiple cells in column
dsx = Delta*pow(1. + (hx*hx), 0.5); // length of h
dsigmadx = (sigmacenter - sigmaleft)/dsx;
}
else {
// dsigmadx = 0.;
// printf("\nError in calculating dsigmadx\n");
// exit(0);
}
sigmaleft = 0.; fsumleft = 0.; sigmaright = 0.; fsumright = 0.; sigmacenter = 0.; fsumcenter = 0.;
//Calculate derivative in Y-Z plane
for (int i = -2; i <= 2; i++){
if (interf(f[0,-1,i])){
sigmaleft += f[0,-1,i]*sigmaf[0,-1,i];
fsumleft += f[0,-1,i];
}
if (interf(f[0,0,i])){
sigmacenter += f[0,0,i]*sigmaf[0,0,i];
fsumcenter += f[0,0,i];
}
if (interf(f[0,1,i])){
sigmaright += f[0,1,i]*sigmaf[0,1,i];
fsumright += f[0,1,i];
}
}
// double fl1,fl0,flm1;
// double fr1,fr0,frm1;
// double sl1,sl0,slm1;
// double sr1,sr0,srm1;
// double hl,hr;
// hl = h.y[-1];
// hr = h.y[1];
// fl1 = f[-1,-1]; fl0 = f[-1,0]; flm1 = f[-1,-1];
// fr1 = f[1,-1]; fr0 = f[1,0]; frm1 = f[1,-1];
// sl1 = sigmaf[-1,-1]; sl0 = sigmaf[-1,0]; slm1 = sigmaf[-1,-1];
// sr1 = sigmaf[1,-1]; sr0 = sigmaf[1,0]; srm1 = sigmaf[1,-1];
double dsy = 0., dsigmady = 0.;
if (fsumleft >= 1.e-6 && fsumright >= 1.e-6){
sigmaleft = sigmaleft/fsumleft; //mean of multiple cells in column
sigmaright = sigmaright/fsumright; //mean of multiple cells in column
dsy = 2.*Delta*pow(1. + (hy*hy), 0.5); // length of h
dsigmady = (sigmaright - sigmaleft)/dsy;
}
else if (fsumleft < 1.e-6 && fsumright > 1.e-6 && fsumcenter > 1.e-6){
sigmacenter = sigmacenter/fsumcenter; //mean of multiple cells in column
sigmaright = sigmaright/fsumright; //mean of multiple cells in column
dsy = Delta*pow(1. + (hy*hy), 0.5); // length of h
dsigmady = (sigmaright - sigmacenter)/dsy;
}
else if (fsumleft > 1.e-6 && fsumright < 1.e-6 && fsumcenter > 1.e-6){
sigmaleft = sigmaleft/fsumleft; //mean of multiple cells in column
sigmacenter = sigmacenter/fsumcenter; //mean of multiple cells in column
dsy = Delta*pow(1. + (hy*hy), 0.5); // length of h
dsigmady = (sigmacenter - sigmaleft)/dsy;
}
else {
// dsigmady = 0.;
// printf("\nError in calculating dsigmady\n");
// exit(0);
}
// if (fabs(fsumleft - f[-1,0]) < 1e-3){ // if there is only one cell in the column
// sigmaleft = sigmaf[-1,0]; //keep the ST coeff same as in the cell, discarding the mean value above
// }
// if (fabs(fsumright - f[1,0]) < 1e-3){ // if there is only one cell in the column
// sigmaright = sigmaf[1,0]; //keep the ST coeff same as in the cell, discarding the mean value above
// }
//~ printf("\n%g\t%g", sigmaleft,sigmaright); fflush(stdout);
//printf("\n ds = %g",ds);
//exit(0);
coord signtangent1;
signtangent1.x = 1;
signtangent1.y = 1;
signtangent1.z = 1;
coord signtangent2;
signtangent2.x = 1;
signtangent2.y = 1;
signtangent2.z = 1;
coord n;
n.x = dsigt->x; n.y = dsigt->y; n.z = dsigt->z; // get normal values stored using dsigt
// normal xz which is in x-z plane 1st quad
if ( (n.x > 0. && n.z > 0.)){
//tangent is in 4th quad
signtangent1.x = 1.;
signtangent1.z = -1.;
}
// normal xz which is in x-z plane 2nd quad
if ( (n.x < 0. && n.z > 0.)){
//tangent is in 1st quad
signtangent1.x = 1.;
signtangent1.z = 1.;
}
// normal xz which is in x-z plane 3rd quad
if ( (n.x < 0. && n.z < 0.) ){
//tangent is in 4th quad
signtangent1.x = 1.;
signtangent1.z = -1.;
}
// normal xz which is in x-z plane 4th quad
if ( (n.x < 0. && n.z > 0.)){
// tangent is in 1st quad
signtangent1.x = 1.;
signtangent1.z = 1.;
}
// normal yz which is in y-z plane 1st quad
if ( (n.y > 0. && n.z > 0.) ){
//tangent is in 4th
signtangent2.y = 1.;
signtangent2.z = -1.;
}
// normal yz which is in y-z plane 2nd quad
if ( (n.y < 0. && n.z > 0.) ){
//1st
signtangent2.y = 1.;
signtangent2.z = 1.;
}
// normal yz which is in y-z plane 3rd quad
if ( (n.y < 0. && n.z < 0.) ){
//4th quad
signtangent2.y = 1.;
signtangent2.z = -1.;
}
// normal yz which is in y-z plane 4th quad
if ( (n.y > 0. && n.z < 0.) ){
signtangent2.y = 1.;
signtangent2.z = 1.;
}
dsigt->x = signtangent1.x * dsigmadx / pow(1. + (hx*hx), 0.5 ); //unity component of tangent vector
dsigt->y = signtangent2.y * dsigmady / pow(1. + (hy*hy), 0.5 );
dsigt->z = signtangent1.z * dsigmadx * fabs(hx)/pow(1. + (hx*hx), 0.5) + signtangent2.z * dsigmady * fabs(hy)/pow(1. + (hy*hy), 0.5);
// dsigt->x = dsigmadx ;
// dsigt->y = dsigmadx ;
// if ((dsigt->x) > 1.){
// double dsix = dsigt->x;
// exit(0);
// }
// if ((dsigt->y) > 10.){
// double dsiy = dsigt->y;
// exit(0);
// }
//~ dsigt->x = dsigmadx / sqrt(1 + sq(hx)); //unity component of tangent vector
// dsigt->x = 0.;
// dsigt->y = 0.;
if (hf_failed_for_curvature == 0)
return (hxx*(1. + sq(hy)) + hyy*(1. + sq(hx)) - 2.*hxy*hx*hy)/
pow(1. + sq(hx) + sq(hy), 3/2.);
else
return nodata;
}
#endif
// foreach_dimension()
// static coord normal2_z (Point point, vector h)
// {
// scalar hz = h.z;
// if (hz[] == nodata)
// return (coord){nodata, nodata, nodata};
// int ori = orientation(hz[]);
// double a = ori ? -1. : 1.;
// coord n;
// n.z = a;
// foreach_dimension(2) {
// if (allocated(-1) && hz[-1] != nodata && orientation(hz[-1]) == ori) {
// if (allocated(1) && hz[1] != nodata && orientation(hz[1]) == ori)
// n.x = a*(hz[-1] - hz[1])/2.;
// else
// n.x = a*(hz[-1] - hz[]);
// }
// else if (allocated(1) && hz[1] != nodata && orientation(hz[1]) == ori)
// n.x = a*(hz[] - hz[1]);
// else
// n.x = nodata;
// }
// return n;
// }
// foreach_dimension()
// static coord normal_z (Point point, vector h) {
// coord n = normal2_z (point, h);
// double nn = fabs(n.x) + fabs(n.y) + fabs(n.z);
// if (nn < nodata) {
// foreach_dimension()
// n.x /= nn;
// return n;
// }
// return (coord){nodata, nodata, nodata};
// }We now need to choose one of the x, y or z height functions to compute the curvature. This is done by the function below which returns the HF curvature given a volume fraction field c and a height function field h.
static double height_marangoni (Point point, scalar c, vector h, coord * dsigt, coord * dsigt_hnc, int i)
{We first define pairs of normal coordinates n (computed by simple differencing of c) and corresponding HF curvature function kappa (defined above).
typedef struct {
double n;
double (* kappa) (Point, vector, coord *);
} NormKappa;
struct { NormKappa x, y, z; } n;
foreach_dimension()
n.x.n = c[1] - c[-1], n.x.kappa = marangoni_x;
double (* kappaf) (Point, vector, coord *) = NULL; NOT_UNUSED (kappaf);
//Palas: Start working here set signs on dsigt
//Palas: Get the relative sign of tangents and store it in dsigt
foreach_dimension()
dsigt->x = c[1] - c[-1];We sort these pairs in decreasing order of |n|.
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);
#endifWe try each curvature function in turn.
double kappa = nodata;
int count_dimension = 1;
foreach_dimension()
{
if (kappa == nodata)
{
kappa = n.x.kappa(point, h, dsigt); // pass dsigt with normal coordinates, it helps in calculating marangoni force
// save the dsigmadx for the highest normal component
if (count_dimension == 1)
{
dsigt_hnc->x = dsigt->x;
dsigt_hnc->y = dsigt->y;
#if dimension == 3
dsigt_hnc->z = dsigt->z;
#endif
}
if (kappa != nodata)
{
kappaf = n.x.kappa;
if (n.x.n < 0.)
{
kappa = -kappa;
}
}
}
count_dimension++;
}
if (kappa != nodata)
{We limit the maximum curvature to 1/\Delta.
if (fabs(kappa) > 1. / Delta)
kappa = sign(kappa) / Delta;We add the axisymmetric curvature if necessary.
#if AXI
double nr, r = y, hx;
if (kappaf == marangoni_x) {
hx = (height(h.x[0,1]) - height(h.x[0,-1]))/2.;
nr = hx*(orientation(h.x[]) ? 1 : -1);
}
else {
r += height(h.y[])*Delta;
hx = (height(h.y[1,0]) - height(h.y[-1,0]))/2.;
nr = orientation(h.y[]) ? -1 : 1;
}
/* limit the minimum radius to half the grid size */
kappa += nr/max (sqrt(1. + sq(hx))*r, Delta/2.);
#endif
}
return kappa;
}General curvature computation
We first need to define “interfacial cells” i.e. cells which contain an interface. A simple test would just be that the volume fraction is neither zero nor one. As usual things are more complicated because of round-off errors. They can cause the interface to be exactly aligned with cell boundaries, so that cells on either side of this interface have fractions exactly equal to zero or one. The function below takes this into account.
The function below computes the mean curvature kappa of the interface defined by the volume fraction c. It uses a combination of the methods above: statistics on the number of curvatures computed which each method is returned in a cstats data structure.
If sigma is different from zero the curvature is multiplied by sigma.
If add is true, the curvature (optionally multiplied by sigma) is added to field kappa.
struct Marangoni {
scalar c, kappa;
vector dsigtv;
//double sigma; // I need variable sigma declared above
bool add;
int i;
};
trace
// cstats marangoni (struct Marangoni p)
cstats marangoni (scalar c, scalar kappa, vector dsigtv, bool add, int i )
{
// scalar c = p.c, kappa = p.kappa;
// vector dsigtv = p.dsigtv;
//~ double sigma = p.sigma ? p.sigma : 1.;
// scalar sigmafL = p.sigmafL ;
int sh = 0, sf = 0, sa = 0, sc = 0;
vector ch = c.height, h = automatic (ch);
if (!ch.x.i)
heights (c, h);
// marangoni_heights (c, sgc);On trees we set the prolongation and restriction functions for the curvature.
//What needs to be done for variable sigma similar to kappa
#if TREE
kappa.refine = kappa.prolongation = curvature_prolongation;
kappa.restriction = curvature_restriction;
dsigtv.x.refine = dsigtv.x.prolongation = curvature_prolongation;
dsigtv.x.restriction = curvature_restriction;
dsigtv.y.refine = dsigtv.y.prolongation = curvature_prolongation;
dsigtv.y.restriction = curvature_restriction;
#if dimension==3
dsigtv.z.refine = dsigtv.z.prolongation = curvature_prolongation;
dsigtv.z.restriction = curvature_restriction;
#endif
#endifWe first compute a temporary curvature k: a “clone” of \kappa.
scalar k[];
scalar_clone (k, kappa);
coord dsigt;
coord dsigt_hnc; //for highest normal component if height function curvature is failing
//~ fprintf (fp, "%g %g\n", t*11.1366559937, max);
//~ fflush (fp);
foreach(reduction(+:sh) reduction(+:sf)) {If we are not in an interfacial cell, we set \kappa to nodata.
if (!interfacial (point, c)){
k[] = nodata;
foreach_dimension(){
dsigtv.x[] = nodata;
// iforce.x[] = 0.;
}
}Otherwise we try the standard HF curvature calculation first, and the “mixed heights” HF curvature second.
else if ((k[] = height_marangoni (point, c, h, &dsigt, &dsigt_hnc, p.i)) != nodata){
foreach_dimension(){
dsigtv.x[] = dsigt.x;
// iforce.x[] = dsigt.x;
}
// diff[] = k[];
//~ fprintf( fp, "%g %g\n",x, dsigtv.x[]);
//~ exit(0);
sh++;
}
else if ((k[] = height_curvature_fit (point, c, h)) != nodata){
//if height_function fails
foreach_dimension()
dsigtv.x[] = dsigt_hnc.x; //use values from the dominant component of the normal
// printf("\n %e %e %e", dsigt_hnc.x, dsigt_hnc.y, dsigt_hnc.z); fflush(stdout);
sf++;
}
}
//~ fclose(fp);
//~ exit(0);
//~ boundary({dsigtv});
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++;
elseEmpty neighborhood: we try centroids as a last resort.
kf = centroids_curvature_fit (point, c), sc++;
//if height_function failed but get the dsigmadx
double junk = height_marangoni (point, c, h, &dsigt, &dsigt_hnc, p.i);
foreach_dimension()
dsigtv.x[] = dsigt_hnc.x;
// printf("\n %e %e %e", dsigt_hnc.x, dsigt_hnc.y, dsigt_hnc.z); fflush(stdout);
}
else
kf = nodata;We add or set kappa.
if (kf == nodata)
kappa[] = nodata;
else if (add)
kappa[] += sigmaf[]*kf;
else
kappa[] = sigmaf[]*kf;
}
//~ printf("\n %d %d %d %d", sh, sf, sa, sc);
//~ exit(0);
return (cstats){sh, sf, sa, sc};
}
event acceleration (i++)
{We check for all VOF interfaces for which \sigma is non-zero.
for (scalar f in interfaces){
// if (f.sigma) {If \phi is already allocated, we add \sigma\kappa, otherwise we allocate a new field and set it to \sigma\kappa.
scalar phi = f.phi;
vector chi = f.chi;
if (phi.i){
marangoni (f, phi, chi, true, i);
}
else {
phi = new scalar;
chi = new vector;
marangoni (f, phi, chi, false, i); // FIX the arguements
f.phi = phi;
f.chi = chi;
}
}We check for all VOF interfaces for which \phi is allocated. The corresponding volume fraction fields will be stored in list.
scalar * list = NULL;
for (scalar f in interfaces)
if (f.phi.i) {
list = list_add (list, f);To avoid undeterminations due to round-off errors, we remove values of the volume fraction larger than one or smaller than zero.
foreach()
f[] = clamp (f[], 0., 1.);
}On trees we need to make sure that the volume fraction gradient is computed exactly like the pressure gradient. This is necessary to ensure well-balancing of the pressure gradient and interfacial force term. To do so, we apply the same prolongation to the volume fraction field as applied to the pressure field.
#if TREE
for (scalar f in list) {
f.prolongation = p.prolongation;
f.dirty = true; // boundary conditions need to be updated
}
#endif
list = list_concat (NULL, {f});
face vector ia = a;
foreach_face(){
vector chi = f.chi;
double chif =
(fabs(chi.x[]) < nodata && fabs(chi.x[-1]) < nodata) ?
(chi.x[] + chi.x[-1])/2. :
fabs(chi.x[]) < nodata ? chi.x[] :
fabs(chi.x[-1]) < nodata ? chi.x[-1] :
0.;
double area = 0;
if (interf(f[])) {
coord n = interface_normal (point, f), p;
double alpha = plane_alpha (f[], n);
// area of the bubble interface
#if AXI
area = y*pow(Delta, dimension - 1)*plane_area_center (n, alpha, &p);
#else
area = pow(Delta, dimension - 1)*plane_area_center (n, alpha, &p);
#endif
}
double deltam = area/dv() ; //+ ( f[0,1] - f[] )/Delta ;
if (addmarangoni == 1){
iforce.x[] = alpha.x[]/fm.x[]*chif*deltam; //save this quantity for time step restriction
ia.x[] += iforce.x[]; // *fabs(deltas);
}
}On trees, we need to restore the prolongation values for the volume fraction field.
#if TREE
for (scalar f in list) {
f.prolongation = fraction_refine;
f.dirty = true; // boundary conditions need to be updated
}
#endif
for (scalar f in list) {
vector chi = f.chi;
delete ((scalar *) {chi});
}
free (list);
}