simulationCases/LiquidOutThinning.c
LiquidOutThinning
Axisymmetric viscoelastic liquid pinch-off simulation using Basilisk and log-conformation rheology.
Fluid assignment: - Fluid 1 (f = 1):
viscoelastic liquid - Fluid 2 (f = 0):
Newtonian gas
Runtime parameters are loaded from a
key=value file through
src-local/params.h.
Input Parameters
This case expects runtime keys such as: -
CaseNo - MAXlevel -
Oh, Oha - De,
Ec - tmax,
dtmax
#define ADAPT_MAXLEVEL
#include "axi.h"
#include "navier-stokes/centered.h"
#include "log-conform-viscoelastic-scalar-2D.h"
#define FILTERED // Smear density and viscosity jumps
#include "two-phaseVE.h"
// #include "log-conform.h" // main version
#include "navier-stokes/conserving.h"
#include "tension.h"
#include "distance.h"
#include "params.h"Output and Adaptivity Controls
// Error tolerances
#define fErr (1e-2) // error tolerance in f VOF
#define KErr (1e-4) // error tolerance in VoF curvature (height-function method)
#define VelErr (1e-2) // velocity error tolerance
#define AErr (1e-2) // conformation error tolerance in liquid
#define epsilon (0.05)Boundary Conditions
u.n[top] = neumann(0.);
p[top] = dirichlet(0.);Global Runtime Variables
These are populated from the parameter file using default fallbacks.
int MAXlevel, MINlevel, maxlevelLocal, CaseNo;
double Oh, Oha, De, Ec, tmax;
double tsnap = 0.05; //snapshot saving interval
char nameOut[128], dumpFile[128], logFile[128];main()
Initializes runtime parameters, configures material properties, and enters the Basilisk event loop.
Parameters
argc: Number of CLI arguments.argv: Argument vector whereargv[1]is an optional parameter file path.
Returns
0: The simulation runs to completion.1: Runtime parameter validation fails before entering the event loop.
int main (int argc, char const *argv[])
{
const char *paramFile = NULL;
stokes = true;
params_init_from_argv(argc, argv);
if (argc > 1)
paramFile = argv[1];
CaseNo = param_int("CaseNo", 1000);
MAXlevel = param_int("MAXlevel", 12);
MINlevel = max(6, (MAXlevel-4)); // minimum grid res
maxlevelLocal = 7;
tmax = param_double("tmax", 2e2);
Oh = param_double("Oh", 1e0);
Oha = param_double("Oha", 1e-2 * Oh);
De = param_double("De", 1e30);
Ec = param_double("Ec", 1e0);
dtmax = param_double("dtmax", 1e-5); // BEWARE of this for stability issues.
if (CaseNo < 1000 || MAXlevel <= 0 || Oh <= 0. || Oha < 0. ||
De < 0. || Ec < 0. || tmax <= 0. || dtmax <= 0. || dtmax > tmax) {
fprintf(ferr, "ERROR: Invalid runtime parameters.\n");
return 1;
}
L0 = 4*pi;
init_grid(1 << MINlevel);
// Create a folder where all simulation snapshots are stored.
system("mkdir -p intermediate");
// Name of the restart file. See writingFiles event.
sprintf(dumpFile, "restart");
sprintf(logFile, "c%d-log", CaseNo);
rho1 = 1.; rho2 = 1e-3;
mu1 = Oh; mu2 = Oha;
G1 = Ec; G2 = 0.0;
lambda1 = De; lambda2 = 0.0;
f.sigma = 1.0;
TOLERANCE = 1e-4;
CFL = 0.5;
if (pid() == 0) {
fprintf(ferr, "CaseNo=%d MAXlevel=%d De=%g Ec=%g Oh=%g tmax=%g dtmax=%g\n",
CaseNo, MAXlevel, De, Ec, Oh, tmax, dtmax);
if (paramFile != NULL)
fprintf(ferr, "Loaded parameters from %s\n", paramFile);
fprintf(ferr, "Logging to %s\n", logFile);
}
run();
}Event: Initialization
Restores from restart if available;
otherwise initializes the thread interface profile.
event init (t = 0)
{
if (!restore(file = dumpFile))
fraction(f, -(1 - epsilon*sin(x/4) - y));
}Adaptive Mesh Refinement
scalar Y[], KAPPA[];
event adapt_maxlevel (i++) {
curvature(f, KAPPA);
position (f, Y, {0,1});
boundary({Y, KAPPA});
double y_min = statsf(Y).min;
if (y_min <= 0.6){
tsnap = 0.01;
}//thinning starts
if (y_min < 0.1){
tsnap = 0.001;
}//thins rapidly
if (y_min < 0.01){
tsnap = 0.0001;
}//near pinchoff
#if ADAPT_MAXLEVEL // thanks @SaumiliJana
static bool broken = false;
if (!broken){
broken = y_min < 1./(1 << maxlevelLocal);
}
if(broken){
maxlevelLocal = 10;
tsnap = 0.05;
} else {
while(((statsf(Y).min)<(5*L0/(1<<maxlevelLocal))) && (maxlevelLocal < MAXlevel)){
maxlevelLocal = maxlevelLocal + 1;
}
}
#else
maxlevelLocal = MAXlevel;
#endif
}
event adapt (i++){Refine/coarsen on interface, velocity, conformation, and curvature.
adapt_wavelet((scalar *) {f, u.x, u.y, A11, A22, A12, AThTh, KAPPA},
(double []) {fErr, VelErr, VelErr, AErr, AErr, AErr, AErr, KErr},
maxlevelLocal, MINlevel);
}Event: writingFiles
Writes restart state and time-stamped snapshots to
intermediate/.
event writingFiles (t = 0; t += tsnap; t <= tmax)
{
dump(file = dumpFile);
sprintf(nameOut, "intermediate/snapshot-%5.4f", t);
dump(file = nameOut);
}Event: stopSimulation
Stops the run when t reaches
tmax.
event stopSimulation (t = tmax)
{
if (pid() == 0)
fprintf(ferr, "Case %d complete. Level %d, De %2.1e, Ec %2.1e, Oh %2.1e\n",
CaseNo, MAXlevel, De, Ec, Oh);Returning non-zero from an event stops the simulation loop.
return 1;
}Event: logWriting
Appends per-iteration diagnostics to
c<CaseNo>-log.
event logWriting (i++)
{
double ke = 0.;
FILE *fp = NULL;Compute total kinetic energy in axisymmetric coordinates.
foreach (reduction(+:ke))
ke += (2*pi*y)*(0.5*rho(f[])*(sq(u.x[]) + sq(u.y[])))*sq(Delta);
position(f, Y, {0, 1});
if (pid() == 0) {
if (i == 0) {
fprintf(ferr, "i dt t ke hm vm\n");
fp = fopen(logFile, "w");
if (fp == NULL) {
fprintf(ferr, "ERROR: cannot open log file %s\n", logFile);
exit(1);
}
fprintf(fp, "CaseNo %d, Level %d, De %g, Ec %g, Oh %g, Oha %g\n",
CaseNo, MAXlevel, De, Ec, Oh, Oha);
fprintf(fp, "i dt t ke hm vm\n");
fprintf(fp, "%d %g %g %g %6.5e %6.5e\n", i, dt, t, ke, statsf(Y).min, normf(u.x).max);
fclose(fp);
} else {
fp = fopen(logFile, "a");
if (fp == NULL) {
fprintf(ferr, "ERROR: cannot open log file %s\n", logFile);
exit(1);
}
fprintf(fp, "%d %g %g %g %6.5e %6.5e\n", i, dt, t, ke, statsf(Y).min, normf(u.x).max);
fclose(fp);
}
fprintf(ferr, "%d %g %g %g %6.5e %6.5e\n", i, dt, t, ke, statsf(Y).min, normf(u.x).max);
assert(ke > -1e-10);
if (ke > 1e2 && i > 1e1) {
fprintf(ferr, "The kinetic energy blew up. Stopping simulation\n");
fp = fopen(logFile, "a");
if (fp != NULL) {
fprintf(fp, "The kinetic energy blew up. Stopping simulation\n");
fclose(fp);
}
dump(file = dumpFile);
return 1;
}
if (ke < 1e-8 && i > 1e1) {
fprintf(ferr, "Kinetic energy too small now. Stopping simulation\n");
dump(file = dumpFile);
fp = fopen(logFile, "a");
if (fp != NULL) {
fprintf(fp, "Kinetic energy too small now. Stopping simulation\n");
fclose(fp);
}
return 1;
}
}
}