|
flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
|
Functions | |
| meniscus (w, theta_deg, dg, sigma=1.0, n=600) | |
| meniscus_mean (w, theta_deg, dg, sigma=1.0, xlo=None, xhi=None) | |
| jurin (w, theta_deg, dg, sigma=1.0) | |
| max_u (s, zlo=None) | |
| relax (s, steps, cfl=0.15, dt_cap=None, probe=0, cb=None, ramp=0.02) | |
| capsule_sdf (nx, ny, nz, xm, r, z0, z1) | |
| jurin_scene (nx=96, ny=4, nz=112, w=16.0, plate=8.0, zp=(12.0, 100.0)) | |
| jurin_colour (nx, ny, nz, subsdf, zi_of_x, sub=4) | |
| set_zero_mean_buoyancy (s, dg, ratio, wos=False) | |
| _channel_columns (sdf, nz) | |
| level_of (cc, eps, xs) | |
| g3_static (theta=30.0, steps=500, nx=96, ny=4, nz=112, w=16.0, plate=8.0, dg=3.0e-3, sigma=1.0, mu=0.2, ratio=10.0, datum=28.0, zp=(12.0, 100.0), flat_start=False, wos=False) | |
| cap_sphere (volume, theta_deg) | |
| cap_colour (nx, ny, nz, cx, cy, zw, R, theta_deg=90.0) | |
| g2_spread (theta_e=30.0, slip=0.1, steps=1500, probe=50, nx=64, nz=40, R=12.0, zw=4.25, sigma=1.0, oh=0.1, dynamic=True, wall_slip=False) | |
| g3_rise (theta_e=30.0, slips=(0.05, 0.3), steps=1500, nx=96, ny=4, nz=112, w=16.0, plate=8.0, dg=3.0e-3, sigma=1.0, mu=0.2, ratio=10.0, datum=28.0, zp=(12.0, 100.0), static_control=True, wall_slip=False, probe=None, lw=False) | |
| g4_incline (theta_a=70.0, theta_r=50.0, bo_fracs=(0.5, 0.7, 1.5, 2.5), steps=1200, nx=48, nz=32, R=8.0, zw=4.25, sigma=1.0, oh=0.2, slip=0.1) | |
Variables | |
| int | PRESS_MAXIT = 300 |
| float | DEG = math.pi / 180.0 |
| dict | _MEN_CACHE = {} |
| list | args = [a for a in sys.argv[1:] if not a.startswith("--")] |
| str | quick = "--quick" in sys.argv |
| list | which = args or ["jurin"] |
| theta | |
| steps | |
| flat_start | |
| wos | |
| probe | |
| list | res = [] |
| sp | |
| wt | |
| am | |
| slip | |
| sl | |
| list | d_meas = res[i][1] - res[i - 1][1] |
| float | d_pred = 9.0 * math.log(res[i - 1][0] / res[i][0]) |
| wall_slip | |
| slips | |
| lw | |
| False | |
| static_control | |
| True | |
WO-V6 (rung V6) — the DYNAMIC contact angle and hysteresis: the gate battery, in Python.
Every gate prints its numbers; nothing is summarised into an adjective. The MODEL (state it with
every result, VOF_PLAN section 6):
theta_Delta^3 = theta_e^3 + 9 Ca_cl ln(Delta/lambda), Ca_cl = mu_l U_cl / sigma
Afkhami, Zaleski & Bussmann, JCP 228:5370 (2009). `lambda` is an EXPLICIT slip length in cells and
is never omitted from a reported number: a VoF contact line's numerical slip is proportional to the
cell size, so without it the imposed angle is silently grid-dependent.
jurin G3-static. CAPILLARY RISE, STATIC. Two 8-cell plates with ROUNDED ends (a capsule SDF, so
there is no sharp 90-degree corner where |grad sdf| != 1) at QUARTER-integer placement,
bounding a gap `w`; the periodic outer channel is a second capillary of width `w_out`.
Both menisci rise, so the reference is the LEVEL DIFFERENCE. Jurin's
`2 sigma cos(theta)/(drho g) (1/w - 1/w_out)` is the Bond -> 0 asymptote and is NOT the
right reference at the Bond numbers a finite box affords; the exact reference is the
static meniscus ODE `sigma z''/(1+z'^2)^{3/2} = drho g (z - z_ref)` with `z'(w/2) =
cot(theta)`, solved here by shooting. Both are printed.
spread G2. SPREADING DROP vs Cox-Voinov. A drop released as a hemisphere on a wall with
`theta_e = 30`: the contact radius a(t) and the apparent angle theta_app(t) are measured
from the shape, `Ca_cl = mu (da/dt)/sigma` from the contact line's own motion, and
`theta_app^3 - theta_e^3` is fitted against `Ca_cl`. The composition property of
Cox-Voinov says the slope is `9 ln(a/lambda)`: the fill supplies `9 ln(Delta/lambda)` and
the resolved hydrodynamics supply `9 ln(a/Delta)`. Tanner's `a ~ t^(1/10)` at late times
is reported alongside.
rise G3-dynamics. The same plate scene from a FLAT interface, with the dynamic angle, over a
slip sweep: the rise curve h(t), the final height against the static equilibrium, and the
damping class (asymptotic vs oscillatory) — the two regimes Gruending et al. (AMM 86:142,
2020) separate.
incline G4. HYSTERESIS: a drop on a tilted wall (the wall is kept axis-aligned and GRAVITY is
tilted, which is the same problem and keeps the SDF exact). Below the critical Bond
number `Bo_c = cos(theta_r) - cos(theta_a)` the contact line must stay PINNED; above it
the drop slides with the front near theta_a and the rear near theta_r.
Usage:
PYTHONPATH=$PWD/build_cuda python tests/study/vof_wetting_dynamic.py [jurin spread rise incline]
... --quick shorter runs
| vof_wetting_dynamic.meniscus | ( | w, | |
| theta_deg, | |||
| dg, | |||
sigma = 1.0, |
|||
n = 600 |
|||
| ) |
The exact 2-D static meniscus in a slot of width `w` with contact angle `theta` on both
walls, in gravity `dg = drho*g`:
sigma z''/(1 + z'^2)^{3/2} = dg (z - z_ref), z'(0) = 0, z'(w/2) = cot(theta)
measured from the flat far-field datum `z_ref = 0`. Shooting on z(0) (monotone: a higher
meniscus has a steeper wall slope). Returns (x, z) on [0, w/2] — the profile is symmetric.
Reduces to Jurin `z = 2 sigma cos(theta)/(dg w)` as Bond -> 0.
Definition at line 59 of file vof_wetting_dynamic.py.
References jurin().
Referenced by g3_static(), and meniscus_mean().
| vof_wetting_dynamic.meniscus_mean | ( | w, | |
| theta_deg, | |||
| dg, | |||
sigma = 1.0, |
|||
xlo = None, |
|||
xhi = None |
|||
| ) |
The MEAN interface height over x in [xlo, xhi] (default the whole slot, x measured from the LEFT wall) — the quantity the colour-integral level read-out measures.
Definition at line 112 of file vof_wetting_dynamic.py.
References meniscus().
Referenced by g3_static().
| vof_wetting_dynamic.jurin | ( | w, | |
| theta_deg, | |||
| dg, | |||
sigma = 1.0 |
|||
| ) |
Definition at line 126 of file vof_wetting_dynamic.py.
Referenced by g3_rise(), g3_static(), and meniscus().
| vof_wetting_dynamic.max_u | ( | s, | |
zlo = None |
|||
| ) |
Definition at line 131 of file vof_wetting_dynamic.py.
Referenced by relax().
| vof_wetting_dynamic.relax | ( | s, | |
| steps, | |||
cfl = 0.15, |
|||
dt_cap = None, |
|||
probe = 0, |
|||
cb = None, |
|||
ramp = 0.02 |
|||
| ) |
`ramp`: the first step is taken at `ramp * dt_cap`, because the interface-local Courant number is read BEFORE the step and is 0 at rest — a full first step on a scene with a strong initial capillary imbalance overshoots the Weymouth-Yue cap and the advector (correctly) throws.
Definition at line 139 of file vof_wetting_dynamic.py.
References max_u().
Referenced by g3_rise(), g3_static(), and g4_incline().
| vof_wetting_dynamic.capsule_sdf | ( | nx, | |
| ny, | |||
| nz, | |||
| xm, | |||
| r, | |||
| z0, | |||
| z1 | |||
| ) |
A plate of thickness 2r centred on x = xm, spanning z in [z0, z1] with SEMICIRCULAR ends: the distance to the segment (xm, z0+r) -> (xm, z1-r) minus r. Flat vertical faces at xm +/- r, no sharp corner anywhere (|grad sdf| = 1 everywhere outside the axis).
Definition at line 170 of file vof_wetting_dynamic.py.
Referenced by jurin_scene().
| vof_wetting_dynamic.jurin_scene | ( | nx = 96, |
|
ny = 4, |
|||
nz = 112, |
|||
w = 16.0, |
|||
plate = 8.0, |
|||
zp = (12.0, 100.0) |
|||
| ) |
The two rounded plates. Returns (sdf, xm_gap, xm_outer, w_out, subsdf); the plate FACES sit at quarter-integer x (WO-S finding 5: at a half-integer the wall cell's tangential MAC faces sit on the SDF zero level and close, and the contact line cannot move). `subsdf(x, z)` is the same SDF as a callable, for sub-cell sampling of the initial colour.
Definition at line 182 of file vof_wetting_dynamic.py.
References capsule_sdf().
Referenced by g3_rise(), and g3_static().
| vof_wetting_dynamic.jurin_colour | ( | nx, | |
| ny, | |||
| nz, | |||
| subsdf, | |||
| zi_of_x, | |||
sub = 4 |
|||
| ) |
C = liquid fraction of the FLUID volume of each cell (VOF_PLAN rule 2), for an interface z = zi(x). The FLUID restriction is not cosmetic: a sub-cell of a cut wall column that is sampled as if it were fluid drops that column's C to `eps`, and a C of 0.75 in the middle of the liquid is a FAKE INTERFACE that the V3 cascade turns into |kappa| ~ 3e6 (measured).
Definition at line 203 of file vof_wetting_dynamic.py.
Referenced by g3_rise(), and g3_static().
| vof_wetting_dynamic.set_zero_mean_buoyancy | ( | s, | |
| dg, | |||
| ratio, | |||
wos = False |
|||
| ) |
`force_z = g (rho_bar - rho)` with `g = dg/(rho_l - rho_g)`: the buoyancy that produces the prescribed `drho g` AND has zero volume mean. THIS IS THE FIX THAT MAKES THE JURIN SCENE WORK, and the defect it removes is what WO-S's G4 measured. The obvious "zero in the gas, -dg in the liquid" form (`[dg/(ratio-1), -dg/(1-1/ratio)]`, which is what WO-S used) has a NON-ZERO volume mean, and in a fully periodic box a non-zero-mean body force accelerates the whole fluid without bound (WO-Q finding 9). Worse than a drift: the accelerating frame contributes its own `-rho a` body force, i.e. it CANCELS PART OF GRAVITY, so the menisci relax towards a smaller level difference the longer the run goes — exactly the -83 % WO-S recorded, with the accompanying non-decaying `max|u|`.
Definition at line 218 of file vof_wetting_dynamic.py.
Referenced by g3_rise(), and g3_static().
|
protected |
The fluid columns of the gap and of the periodic outer channel, as index arrays. EVERY fluid column is included, cut ones too: the level read-out is eps-weighted, so the full-width mean is what the exact identity below refers to.
Definition at line 244 of file vof_wetting_dynamic.py.
Referenced by g3_rise(), and g3_static().
| vof_wetting_dynamic.level_of | ( | cc, | |
| eps, | |||
| xs | |||
| ) |
Definition at line 259 of file vof_wetting_dynamic.py.
Referenced by g3_rise(), and g3_static().
| vof_wetting_dynamic.g3_static | ( | theta = 30.0, |
|
steps = 500, |
|||
nx = 96, |
|||
ny = 4, |
|||
nz = 112, |
|||
w = 16.0, |
|||
plate = 8.0, |
|||
dg = 3.0e-3, |
|||
sigma = 1.0, |
|||
mu = 0.2, |
|||
ratio = 10.0, |
|||
datum = 28.0, |
|||
zp = (12.0, 100.0), |
|||
flat_start = False, |
|||
wos = False |
|||
| ) |
Definition at line 265 of file vof_wetting_dynamic.py.
References _channel_columns(), jurin(), jurin_colour(), jurin_scene(), level_of(), meniscus(), meniscus_mean(), relax(), and set_zero_mean_buoyancy().
| vof_wetting_dynamic.cap_sphere | ( | volume, | |
| theta_deg | |||
| ) |
Definition at line 333 of file vof_wetting_dynamic.py.
Referenced by cap_colour().
| vof_wetting_dynamic.cap_colour | ( | nx, | |
| ny, | |||
| nz, | |||
| cx, | |||
| cy, | |||
| zw, | |||
| R, | |||
theta_deg = 90.0 |
|||
| ) |
Definition at line 339 of file vof_wetting_dynamic.py.
References cap_sphere().
Referenced by g2_spread(), and g4_incline().
| vof_wetting_dynamic.g2_spread | ( | theta_e = 30.0, |
|
slip = 0.1, |
|||
steps = 1500, |
|||
probe = 50, |
|||
nx = 64, |
|||
nz = 40, |
|||
R = 12.0, |
|||
zw = 4.25, |
|||
sigma = 1.0, |
|||
oh = 0.1, |
|||
dynamic = True, |
|||
wall_slip = False |
|||
| ) |
Definition at line 352 of file vof_wetting_dynamic.py.
References cap_colour().
| vof_wetting_dynamic.g3_rise | ( | theta_e = 30.0, |
|
slips = (0.05, 0.3), |
|||
steps = 1500, |
|||
nx = 96, |
|||
ny = 4, |
|||
nz = 112, |
|||
w = 16.0, |
|||
plate = 8.0, |
|||
dg = 3.0e-3, |
|||
sigma = 1.0, |
|||
mu = 0.2, |
|||
ratio = 10.0, |
|||
datum = 28.0, |
|||
zp = (12.0, 100.0), |
|||
static_control = True, |
|||
wall_slip = False, |
|||
probe = None, |
|||
lw = False |
|||
| ) |
G3-dynamics: the same plate scene from a FLAT interface, so the contact line has to travel. The static equilibrium level difference is Jurin's, EXACTLY (see g3_static), so the gate is the final height against it; the damping class (asymptotic vs oscillatory) is the second half of the Gruending et al. (AMM 86:142, 2020) comparison.
Definition at line 448 of file vof_wetting_dynamic.py.
References _channel_columns(), jurin(), jurin_colour(), jurin_scene(), level_of(), relax(), and set_zero_mean_buoyancy().
| vof_wetting_dynamic.g4_incline | ( | theta_a = 70.0, |
|
theta_r = 50.0, |
|||
bo_fracs = (0.5, 0.7, 1.5, 2.5), |
|||
steps = 1200, |
|||
nx = 48, |
|||
nz = 32, |
|||
R = 8.0, |
|||
zw = 4.25, |
|||
sigma = 1.0, |
|||
oh = 0.2, |
|||
slip = 0.1 |
|||
| ) |
The wall is kept axis-aligned and GRAVITY is tilted — the same problem, an exact SDF. Bo = drho g V^(2/3) sin(alpha) / sigma against Bo_c = cos(theta_r) - cos(theta_a) (ElSherbini & Jacobi 2006's retention relation in its simplest form).
Definition at line 527 of file vof_wetting_dynamic.py.
References cap_colour(), and relax().
| int vof_wetting_dynamic.PRESS_MAXIT = 300 |
Definition at line 51 of file vof_wetting_dynamic.py.
| float vof_wetting_dynamic.DEG = math.pi / 180.0 |
Definition at line 52 of file vof_wetting_dynamic.py.
|
protected |
Definition at line 56 of file vof_wetting_dynamic.py.
| list vof_wetting_dynamic.args = [a for a in sys.argv[1:] if not a.startswith("--")] |
Definition at line 584 of file vof_wetting_dynamic.py.
| str vof_wetting_dynamic.quick = "--quick" in sys.argv |
Definition at line 585 of file vof_wetting_dynamic.py.
| list vof_wetting_dynamic.which = args or ["jurin"] |
Definition at line 586 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.theta |
Definition at line 588 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.steps |
Definition at line 588 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.flat_start |
Definition at line 591 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.wos |
Definition at line 593 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.probe |
Definition at line 595 of file vof_wetting_dynamic.py.
| list vof_wetting_dynamic.res = [] |
Definition at line 601 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.sp |
Definition at line 603 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.wt |
Definition at line 603 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.am |
Definition at line 603 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.slip |
Definition at line 603 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.sl |
Definition at line 603 of file vof_wetting_dynamic.py.
Definition at line 609 of file vof_wetting_dynamic.py.
Definition at line 610 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.wall_slip |
Definition at line 621 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.slips |
Definition at line 634 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.lw |
Definition at line 634 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.False |
Definition at line 635 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.static_control |
Definition at line 635 of file vof_wetting_dynamic.py.
| vof_wetting_dynamic.True |
Definition at line 637 of file vof_wetting_dynamic.py.