|
flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
|
Functions | |
| _scriven_integral (beta, rr, lo=0.0) | |
| scriven_beta (ja, rr) | |
| scriven_T (r, R, beta, rr, dT) | |
| initial_temperature (n, ctr, R, beta, rr, dT, mode="similarity", sub=4) | |
| sphere_colour_chunked (n, ctr, R, sub) | |
| sphere_colour (n, cx, cy, cz, R, sub=4) | |
| apply_p3g (s, order=1, op_mdot=None, gfm_order=None, curv_dist=None, carry=None, deposit=None) | |
| run (n, ja, ratio, r0, r1, cfl=0.2, alpha_l=1.0, sweeps=200, plane=True, consistent=True, quad=True, muscl=False, init="similarity", sub=4, area_mode=None, verbose=True, budget=0, carry=False, fitkap=False, p3g=None) | |
| plane_colour (n, nrm, sub=8, shift=0.37) | |
| plane_colour_periodic (n, nrm, sub=8, shift=0.37) | |
| cylinder_colour_chunked (n, ctr, R, sub) | |
| solenoidal_faces (n, amp, drift) | |
| area_advect (n=128, R=16.0, sub=16, steps=100, cfl=0.2, amp=0.0, drift=(0.5, 0.25, 0.125), modes=(0, 3, 4, 6, 7)) | |
| _mc_area (c) | |
| area_probe (n, radii, ratio=100.0, sub=4, mode=None, shape="sphere") | |
| _sph_moments (w, ax, ctr, lmax=4) | |
| _cubic_bins (n, ctr, nb=4) | |
| regress_probe (n=128, radii=(16.0,), deltas=(0.05, 0.1, 0.2), sub=16, modes=(0, 6), ratio=100.0, advect_steps=0, drift=(0.5, 0.25, 0.125), cfl=0.2, nbin=4) | |
| _mdot_scene (n, R, ja, ratio, sub, alpha_l, area_mode, quad, plane, geom, dt, prof, kap=False, p3g=None) | |
| mdot_probe (n, radii, ja=0.5, ratio=100.0, sub=16, alpha_l=1.0, area_mode=None, quad=True, plane=True, dt=None, geoms=("sphere", "plane"), profs=("scriven",), kap=False, p3g=None) | |
| carry_probe (n, steps, ratio=100.0, carry=False, sub=16, grad=0.05, mdot=2.0e-3, p3g=None) | |
| main () | |
Variables | |
| tuple | AREA_MODES |
| _GL = np.polynomial.legendre.leggauss(400) | |
WO-P23 rung P3 — SCRIVEN bubble growth (Scriven, Chem. Eng. Sci. 10:1, 1959).
A spherical vapour bubble growing in uniformly superheated liquid, thermally controlled:
R(t) = 2 beta sqrt(alpha_l t) ,
Ja = rho_l c_pl (T_inf - T_sat) / (rho_v h_lv)
= 2 beta^2 int_0^1 exp( -beta^2 [ (1-x)^-2 - 2(1 - rho_v/rho_l) x - 1 ] ) dx (Scriven)
T(r,t) = T_inf - (rho_v h_lv)/(rho_l c_pl) * 2 beta^2
int_{1-R/r}^{1} exp( -beta^2 [ (1-x)^-2 - 2(1 - rho_v/rho_l) x - 1 ] ) dx .
The integral is tabulated numerically here (Gauss-Legendre on a substitution that resolves the
essential singularity at x -> 1); `beta` follows by bisection.
WHAT THE RUN MEASURES. R(t) from the LIQUID VOLUME DEFICIT, R = (3 sum(1-C) / 4pi)^(1/3) — a
conserved-quantity read-out, not a contour, so it does not depend on any interface post-processing.
The gate is |R_num - R_exact| / R_exact over the last half of the run.
INITIALISATION (`--init`, WO-P3b). Scriven's solution carries a thermal boundary layer of
thickness ~R0/(2 beta^2) at t0, and the classic trap in this benchmark is to start from a UNIFORM
superheat with a sharp bubble, so that the first steps evaporate the superheat sitting AT the
interface and the radius keeps a permanent offset. `--init similarity` (the DEFAULT, and what
this driver has always done) samples T(r, t0) from the profile above at the cell centres, with
R0 = 2 beta sqrt(alpha_l t0) by construction (t0 is derived from R0); `--init cellavg` is the
same profile CELL-AVERAGED by 4^3 subsampling; `--init uniform` is the trap itself, kept as the
CONTROL that shows what it costs.
BOUNDARIES. Outflow on all six faces (the net vapour production is a real volume flux and has to
leave; with pure liquid at every face and the reference density set to rho_l the boundary
coefficient `applyBoundaryOpenness` re-imposes IS the variable-density one, so WO-R2 item 1 is
side-stepped by construction) and T = T_inf Dirichlet on all six.
Usage:
PYTHONPATH=$PWD/build_cuda python tests/study/vof_scriven.py [--n 128] [--ja 0.5,2,10]
|
protected |
int_lo^1 exp(-beta^2[(1-x)^-2 - 2(1-rr) x - 1]) dx, by the substitution x = 1 - 1/u (u in [1/(1-lo), inf)) folded onto a finite interval with u = 1/v.
Definition at line 52 of file vof_scriven.py.
Referenced by scriven_beta(), and scriven_T().
| vof_scriven.scriven_beta | ( | ja, | |
| rr | |||
| ) |
Definition at line 65 of file vof_scriven.py.
References _scriven_integral().
Referenced by _mdot_scene(), mdot_probe(), and run().
| vof_scriven.scriven_T | ( | r, | |
| R, | |||
| beta, | |||
| rr, | |||
| dT | |||
| ) |
T_inf - dT * (2 beta^2 / Ja) * int_{1-R/r}^1 (...) == the profile above, normalised so that
T(R) = T_inf - dT.
Definition at line 76 of file vof_scriven.py.
References _scriven_integral().
Referenced by _mdot_scene(), initial_temperature(), and run().
| vof_scriven.initial_temperature | ( | n, | |
| ctr, | |||
| R, | |||
| beta, | |||
| rr, | |||
| dT, | |||
mode = "similarity", |
|||
sub = 4 |
|||
| ) |
T(r, t0) - T_sat on the cell centres, for the three initialisations of `--init`.
'similarity' : Scriven's similarity profile sampled AT the cell centre. This is what the
driver has always done and what Sato & Niceno (JCP 2013) and Malan et al.
(2021) do; it is the shipped default and this branch is byte-identical to the
pre-WO-P3b code.
'cellavg' : the same profile, CELL-AVERAGED by sub^3 subsampling (a finite-volume initial
state rather than a point sample -- the O(h^2 T'') half of the same question).
'uniform' : uniform superheat T_inf in the liquid, T_sat inside the bubble, i.e. NO thermal
boundary layer at t0. The classic trap, kept as the control.
Definition at line 86 of file vof_scriven.py.
References mean(), and scriven_T().
Referenced by run().
| vof_scriven.sphere_colour_chunked | ( | n, | |
| ctr, | |||
| R, | |||
| sub | |||
| ) |
Liquid fraction of a sphere by sub^3 subsampling, one cell-plane at a time. WO-P3c: the AREA probe needs a colour field whose SLIVER cells survive. `sub^3` subsampling quantizes C to multiples of 1/sub^3, so every cell whose true liquid fraction is below 1/(2 sub^3) is rounded to exactly 0 or 1 and DROPS OUT of the interface entirely — at sub = 4 that is a quarter of the interfacial cells of a sphere and 5-9 % of its area, while the VOLUME (and hence R0) moves by 1e-4 %. That is the whole of WO-P3b's "the PLIC area of a sphere is 5-9 % low": see the WO-P3c findings. The chunked loop is what makes sub = 32 affordable (sub = 32 on R = 28 would otherwise materialise a 2000^3 sample cloud).
Definition at line 122 of file vof_scriven.py.
References mean().
Referenced by _mdot_scene(), area_advect(), area_probe(), regress_probe(), and run().
| vof_scriven.sphere_colour | ( | n, | |
| cx, | |||
| cy, | |||
| cz, | |||
| R, | |||
sub = 4 |
|||
| ) |
Liquid fraction (C = 1 liquid, 0 vapour) of a sphere of radius R, by sub^3 subsampling.
Definition at line 147 of file vof_scriven.py.
Referenced by regress_probe().
| vof_scriven.apply_p3g | ( | s, | |
order = 1, |
|||
op_mdot = None, |
|||
gfm_order = None, |
|||
curv_dist = None, |
|||
carry = None, |
|||
deposit = None |
|||
| ) |
WO-P3g: the second-order interfacial energy operator, as a package and as an ablation. `order = 2` turns on all four pieces (operator-flux mdot, the Gibou-Fedkiw three-point row, curvature-consistent distances from the V3 cascade, and WO-P3f's enthalpy-conserving Dirichlet overwrite); the four keyword overrides then switch individual pieces back off or on, which is how the ablation rows of the findings are produced. `order = 1` with all overrides None is the shipped scheme, bitwise.
Definition at line 166 of file vof_scriven.py.
Referenced by _mdot_scene(), carry_probe(), and run().
| vof_scriven.run | ( | n, | |
| ja, | |||
| ratio, | |||
| r0, | |||
| r1, | |||
cfl = 0.2, |
|||
alpha_l = 1.0, |
|||
sweeps = 200, |
|||
plane = True, |
|||
consistent = True, |
|||
quad = True, |
|||
muscl = False, |
|||
init = "similarity", |
|||
sub = 4, |
|||
area_mode = None, |
|||
verbose = True, |
|||
budget = 0, |
|||
carry = False, |
|||
fitkap = False, |
|||
p3g = None |
|||
| ) |
Definition at line 188 of file vof_scriven.py.
References apply_p3g(), initial_temperature(), scriven_beta(), scriven_T(), and sphere_colour_chunked().
Referenced by main().
| vof_scriven.plane_colour | ( | n, | |
| nrm, | |||
sub = 8, |
|||
shift = 0.37 |
|||
| ) |
Liquid fraction (C = 1 liquid) of the half space n.(x - centre) < shift, by sub^3 subsampling. The sub-cell shift matters: a grid-aligned plane placed exactly on a cell face has NO mixed cell at all (CLAUDE.md, the VoF dt-limiter note), so the probe would read zero interfacial cells and no area.
Definition at line 473 of file vof_scriven.py.
References mean().
Referenced by area_probe().
| vof_scriven.plane_colour_periodic | ( | n, | |
| nrm, | |||
sub = 8, |
|||
shift = 0.37 |
|||
| ) |
Liquid fraction of the PERIODIC tilted-plane family `0 <= (nrm . x) mod n < n/2`.
WO-P3d. A single half-space in a PERIODIC box is not a single plane: the wrap turns the
domain faces into a second interface, and a JOINED surface reconstruction reports it (measured:
the (1,1,0) row of `--area-probe=-2` comes out +5 % against the one-plane reference purely
because of the seam, while a per-cell area misses it since the seam has no mixed cell). The
repair is a scene that is periodic BY CONSTRUCTION: with an INTEGER normal `nrm`, the level
sets of `f = nrm . x (mod n)` are closed flat surfaces of the torus, and the co-area formula
gives their total area in closed form,
integral |grad f| dV = |nrm|_2 n^3 = n * A(one level) => A(one level) = |nrm|_2 n^2 ,
so the two level sets bounding `f < n/2` carry EXACTLY `2 |nrm|_2 n^2`. No edge convention, no
seam, no reference uncertainty — for (0,0,1) it is 2 n^2, for (1,1,0) it is 2 sqrt(2) n^2.
Definition at line 487 of file vof_scriven.py.
References mean().
Referenced by area_probe().
| vof_scriven.cylinder_colour_chunked | ( | n, | |
| ctr, | |||
| R, | |||
| sub | |||
| ) |
Liquid fraction of an INFINITE cylinder of radius R along z (a curved interface with ONE non-zero principal curvature — the control that separates a metric error from a curvature error), by sub^2 subsampling of the transverse plane. Exact in z by construction, so its reference area 2 pi R n_z carries no z discretisation at all.
Definition at line 516 of file vof_scriven.py.
References mean().
Referenced by area_probe().
| vof_scriven.solenoidal_faces | ( | n, | |
| amp, | |||
| drift | |||
| ) |
A face velocity field that is EXACTLY discretely divergence-free on the staggered grid.
Two cellular (Taylor-Green) cells plus a uniform drift:
u = A sin(k x_f) cos(k y_c) , v = -A cos(k x_c) sin(k y_f) + A sin(k y_f) cos(k z_c) ,
w = -A cos(k y_c) sin(k z_f) , k = 2 pi / n , plus the constant `drift`.
The discrete divergence vanishes to the LAST BIT, not to O(h^2), and that matters: `advect_vof`
refuses a field whose `max_open_divergence_projected()` exceeds 1e-10 because Weymouth-Yue's
exact conservation is conditional on it. The identity is
`sin(k(x+h)) - sin(k x) = 2 sin(kh/2) cos(k(x + h/2))`, and `x + h/2` of a FACE is exactly the
CELL CENTRE the transverse factor is evaluated at — so the two axes' differences cancel term by
term for each cellular pair.
Definition at line 532 of file vof_scriven.py.
Referenced by area_advect(), and regress_probe().
| vof_scriven.area_advect | ( | n = 128, |
|
R = 16.0, |
|||
sub = 16, |
|||
steps = 100, |
|||
cfl = 0.2, |
|||
amp = 0.0, |
|||
drift = (0.5, 0.25, 0.125), |
|||
modes = (0, 3, 4, 6, 7) |
|||
| ) |
WO-P3d gate (b): is the JOINED area BOUNDED under Weymouth-Yue advection? An a-priori probe measures a construction on an EXACT colour field. A running one never sees one: WY leaves round-off residue in every cell its sweeps touch (down to 1e-300 -- the residue the V4 curvature needed `interfaceEps` for and the W0 block container needed `bubbleEps` for), and the interfacial-cell density climbs from the initialisation's value to ~1.5/h^2 within ten steps. A per-cell area sums over those cells, so the question "does the area drift with the WISP population" is a real one; a joined sheet is built from the C = 1/2 crossing and should be blind to them. Both are measured here, on the SAME field, step by step. `amp = 0` is the pure TRANSLATION control, where the exact answer stays `4 pi R^2` for ever.
Definition at line 560 of file vof_scriven.py.
References solenoidal_faces(), and sphere_colour_chunked().
Referenced by main().
|
protected |
Marching-cubes area of the C = 1/2 level set — an INDEPENDENT geometric reference for the summed PLIC area (it agrees with 4 pi R^2 to 0.5 % on the exact spheres below).
Definition at line 625 of file vof_scriven.py.
Referenced by area_probe().
| vof_scriven.area_probe | ( | n, | |
| radii, | |||
ratio = 100.0, |
|||
sub = 4, |
|||
mode = None, |
|||
shape = "sphere" |
|||
| ) |
A-PRIORI probe (WO-P3b): the summed PLIC interface area of an EXACT sphere, against 4 pi R^2. No time stepping, no energy solve, no velocity — the exact sphere fractions are set, one `apply_phase_change(0.0)` builds the interface, and `phase_change_diagnostics()['interface_area']` is read. This isolates the geometry of `plicArea` + the MYC normals from every other part of the rung, and it is the quantity the R(t) gate integrates: the bubble grows as int mdot dA.
Definition at line 636 of file vof_scriven.py.
References _mc_area(), cylinder_colour_chunked(), plane_colour(), plane_colour_periodic(), and sphere_colour_chunked().
Referenced by main().
|
protected |
Real spherical-harmonic moments of a signed cell weight `w` (a removal density), returned as the per-l RMS coefficient normalised by |sum w|. The regression shifts each cell's plane along that cell's OWN normal, so a systematic under-shift on (say) the octant diagonals would leave the bubble faceted. A cubic lattice can only produce CUBIC-harmonic anisotropy, whose leading term is l = 4 (l = 2 vanishes by the three mirror symmetries), so the l = 2 row is the control and the l = 4 row is the signal.
Definition at line 709 of file vof_scriven.py.
Referenced by regress_probe().
|
protected |
(ctr is a 3-tuple of cell-index centres.)
Direction classes by the cubic invariant s = u_x^4 + u_y^4 + u_z^4, which runs from 1/3 on the BODY DIAGONAL (111) through 1/2 on a FACE diagonal (110) to 1 on an AXIS (100). Binning the removed volume by s and dividing by the same bins of the EXACT removal is a direct, reference-free read-out of whether the regression is isotropic.
Definition at line 743 of file vof_scriven.py.
Referenced by regress_probe().
| vof_scriven.regress_probe | ( | n = 128, |
|
radii = (16.0,), |
|||
deltas = (0.05, 0.1, 0.2), |
|||
sub = 16, |
|||
modes = (0, 6), |
|||
ratio = 100.0, |
|||
advect_steps = 0, |
|||
drift = (0.5, 0.25, 0.125), |
|||
cfl = 0.2, |
|||
nbin = 4 |
|||
| ) |
WO-P3e — the a-priori INTERFACE REGRESSION probe. No time stepping, no energy solve, no
velocity: an exact sphere goes in, ONE `apply_phase_change(dt)` with a uniform prescribed mdot
runs the plane shift + clip-and-redistribute, and the colour field that comes out is compared
against the analytically known answer.
With `rho_l = 1` and `mdot = 1` the step's normal displacement is exactly `delta = dt`, so the
exact liquid volume removed from a sphere of radius R is the shell
dV = 4/3 pi ((R+delta)^3 - R^3) = 4 pi R^2 delta (1 + delta/R + delta^2/(3 R^2))
(the bubble is the GAS, so evaporation GROWS it: R -> R + delta), the new radius from the
volume deficit is R + delta exactly, and the new interfacial area is 4 pi (R+delta)^2. Those
three are the gate. The fourth read-out is ISOTROPY: the shift acts along each cell's own
normal with the cell's own area, so an under-shift on the octant diagonals would leave the
bubble faceted -- measured both as the ratio of the removed volume to the exact removed volume
in bins of the cubic invariant `u_x^4 + u_y^4 + u_z^4`, and as the l = 2 / l = 4 spherical
harmonic moments of the removal density.
`--regress-advect N` runs the sphere through N Weymouth-Yue steps of the PURE TRANSLATION field
of gate (b) first, so the fractions are the ones a running solver actually carries (WY re-creates
the sliver/wisp population within ten steps) while the exact reference stays a sphere.
Definition at line 760 of file vof_scriven.py.
References _cubic_bins(), _sph_moments(), solenoidal_faces(), sphere_colour(), and sphere_colour_chunked().
Referenced by main().
|
protected |
One a-priori mdot evaluation: `geom` x `prof`, the 2x2 that separates the two curvatures. `geom` = 'sphere' (the exact sphere, sub^3 fractions) or 'plane' (a flat interface normal to x at a sub-cell offset, the same sub^3 fractions). `prof` = 'scriven' (Scriven's similarity profile of a bubble of radius R at the matching time, as a function of the signed distance to the interface -- so the sphere and plane rows carry IDENTICAL T', T'' at the interface) or 'linear' (T = T'(R) d exactly, zero profile curvature). ONE `apply_phase_change(dt)` evaluates the shipped estimator: no energy solve, no velocity, no time stepping. The only things measured are the one-sided gradient fit and the area on that field. `plane x linear` is the exactness control (the fit's model is the exact state); `sphere x linear` isolates the INTERFACE's curvature; `plane x scriven` isolates the PROFILE's curvature and its resolution; `sphere x scriven` is the run's own configuration.
Definition at line 882 of file vof_scriven.py.
References apply_p3g(), mean(), scriven_beta(), scriven_T(), and sphere_colour_chunked().
Referenced by mdot_probe().
| vof_scriven.mdot_probe | ( | n, | |
| radii, | |||
ja = 0.5, |
|||
ratio = 100.0, |
|||
sub = 16, |
|||
alpha_l = 1.0, |
|||
area_mode = None, |
|||
quad = True, |
|||
plane = True, |
|||
dt = None, |
|||
geoms = ("sphere", "plane"), |
|||
profs = ("scriven",), |
|||
kap = False, |
|||
p3g = None |
|||
| ) |
WO-P3f gate (b): the a-priori CURVATURE BIAS of the one-sided mdot fit. For each radius the exact sphere carries Scriven's similarity profile at the matching time and the shipped estimator is evaluated ONCE. The area-weighted mdot is compared with the analytic `mdot = rho_v beta sqrt(alpha/t)`; the flat-interface row with the SAME profile is the control.
Definition at line 984 of file vof_scriven.py.
References _mdot_scene(), and scriven_beta().
Referenced by main().
| vof_scriven.carry_probe | ( | n, | |
| steps, | |||
ratio = 100.0, |
|||
carry = False, |
|||
sub = 16, |
|||
grad = 0.05, |
|||
mdot = 2.0e-3, |
|||
p3g = None |
|||
| ) |
WO-P3f, the a-priori gate of `--carry`: a PLANAR interface swept through cells at a PRESCRIBED mass flux, with a linear superheat profile in the liquid. Everything about the scene is chosen so the ONLY enthalpy book-keeping under test is the interfacial cells' Dirichlet overwrite: `mdot` is prescribed (no gradient fit), the phase conductivities are ~0 (no diffusion), the interface is flat (no curvature) and the profile is linear (no profile curvature). Per step the instrument prints the identity the option must satisfy exactly -- what the deposit hands back plus what it could not place equals what the overwrite destroys -- and the trajectory of the total enthalpy `sum rho c_p(C) (T - T_sat)` over the inner cells, which is the quantity the option exists to stop leaking.
Definition at line 1037 of file vof_scriven.py.
References apply_p3g(), and mean().
Referenced by main().
| vof_scriven.main | ( | ) |
Definition at line 1124 of file vof_scriven.py.
References area_advect(), area_probe(), carry_probe(), main(), mdot_probe(), regress_probe(), and run().
Referenced by main().
| tuple vof_scriven.AREA_MODES |
Definition at line 46 of file vof_scriven.py.
|
protected |
Definition at line 49 of file vof_scriven.py.