43from vof_surface_tension
import (HYSING, Scale, Solve, cylinder_fractions,
58 print(
"\n" +
"=" * 100)
59 print(
"G3 STATIC DROPLET, computed curvature — Ca = mu max|u| / sigma, both grids")
61 print(
" The balanced-force identity is exact on both grids (the ctest's T2: the FACE field")
62 print(
" stays at machine zero with a constant kappa). What is left is the curvature error.")
63 print(
" On the collocated grid the CELL number additionally carries the invisible")
64 print(
" checkerboard, so both are printed.\n")
65 rungs = [(16, 4.0), (32, 8.0)]
if QUICK
else [(16, 4.0), (32, 8.0), (48, 12.0)]
68 for label, cls
in GRIDS:
72 s.set_pressure_geometry(np.full((n, n, n), 10.0, order=
"F"))
73 s.set_pressure_chebyshev(
True, 500, 1e-14)
75 s.set_vof(sphere_fractions((n, n, n), R, (n / 2 + 0.13, n / 2 + 0.27, n / 2 + 0.11)))
76 s.set_property_model(
"rho",
"linear",
"C", [1.0, 0.0])
77 s.set_surface_tension(1.0)
78 s.set_dt(0.5 * s.capillary_dt())
83 ca = 0.1 * maxvel(s) / 1.0
85 row[label] = (ca, caf, h)
86 print(f
" D/dx = {2*R:5.1f} {label} Ca(cell) = {ca:.3e} Ca(face) = {caf:.3e}")
88 st, co = row[
"staggered "][0], row[
"collocated"][0]
89 print(f
" D/dx = {2*R:5.1f} collocated / staggered (cell Ca) = {co/st:.2f} x\n")
94 print(
"\n" +
"=" * 100)
95 print(
"G5 CAPILLARY WAVE, 32 cells/lambda — omega against the EXACT viscous two-fluid mode")
97 rungs = [(32, 0.005)]
if QUICK
else [(32, 0.005), (64, 0.005)]
99 nz, ny, rho, sigma = nx, 4, 1.0, 1.0
101 k = 2 * math.pi / lam
103 omega_th = math.sqrt(sigma * k ** 3 / (2 * rho))
104 s_ex, _ = wave_mode(k, nu, sigma, rho, H=nz / 2.0)
105 omega_ex, gamma_ex = s_ex.imag, -s_ex.real
106 for label, cls
in GRIDS:
110 s.set_domain_bc(
"-z",
"wall", (0, 0, 0))
111 s.set_domain_bc(
"+z",
"wall", (0, 0, 0))
112 s.set_pressure_geometry(np.full((nx, ny, nz), 10.0, order=
"F"))
113 s.set_pressure_chebyshev(
True, 500, 1e-11)
115 xe = np.arange(nx + 1)
116 zi = nz / 2.0 + a0 * (np.sin(k * xe[1:]) - np.sin(k * xe[:-1])) / (k * 1.0)
117 C = np.zeros((nx, ny, nz))
119 C[:, :, kk] = np.clip(zi - kk, 0.0, 1.0)[:,
None]
120 s.set_vof(np.asfortranarray(C))
121 s.set_property_model(
"rho",
"linear",
"C", [rho, 0.0])
122 s.set_surface_tension(sigma)
123 dt = 0.5 * s.capillary_dt()
125 nsteps = int(2.5 * (2 * math.pi / omega_th) / dt)
128 for i
in range(nsteps):
131 col = s.get_vof().sum(axis=2)[:, 0]
132 t.append((i + 1) * dt)
133 amp.append(float(np.dot(col - nz / 2.0,
134 np.cos(k * (np.arange(nx) + 0.5))) * 2.0 / nx))
135 t, amp = np.array(t), np.array(amp)
136 zc = zero_crossings(t, amp)
137 omega_num = math.pi / np.mean(np.diff(zc))
if len(zc) >= 3
else float(
"nan")
138 pk = [i
for i
in range(1, len(amp) - 1)
139 if abs(amp[i]) > abs(amp[i - 1])
and abs(amp[i]) > abs(amp[i + 1])]
140 gamma_num = (-math.log(abs(amp[pk[-1]]) / abs(amp[pk[0]])) / (t[pk[-1]] - t[pk[0]])
141 if len(pk) >= 2
else float(
"nan"))
142 print(f
" nx = {nx} {label} omega {omega_num:.5f} vs inviscid {omega_th:.5f} "
143 f
"({100*(omega_num/omega_th-1):+.2f} %) vs EXACT viscous {omega_ex:.5f} "
144 f
"({100*(omega_num/omega_ex-1):+.2f} %)")
145 print(f
" gamma {gamma_num:.3e} vs exact {gamma_ex:.3e} "
146 f
"({100*(gamma_num/gamma_ex-1):+.1f} %); {h}")
152 print(
"\n" +
"=" * 100)
153 print(f
"G4 HYSING RISING BUBBLE case 1 (ratio 10), nx = {nx} — both grids")
155 print(
" `enable_vof_momentum` is STAGGERED-ONLY at this rung (the collocated construction")
156 print(
" needs Favre face states, AMR-Wind's pattern), so the collocated column runs without")
157 print(
" it and the honest staggered comparison is the momentum-consistency-OFF one. Both")
158 print(
" staggered columns are printed; V2b is worth ~14 % here.\n")
162 R = sc.len_to_cells(0.25)
163 runs = [(
"staggered (V2b ON )", pf.Solver,
True),
164 (
"staggered (V2b OFF)", pf.Solver,
False),
165 (
"COLLOCATED (V2b n/a)", pf.SolverColocated,
False)]
167 for label, cls, vmom
in runs:
170 s.set_mu(sc.mu(p[
"mu1"]))
171 s.set_domain_bc(
"-z",
"wall", (0, 0, 0))
172 s.set_domain_bc(
"+z",
"wall", (0, 0, 0))
173 s.set_pressure_geometry(np.full((nx, ny, nz), 10.0, order=
"F"))
174 s.set_pressure_chebyshev(
True, 600, 1e-12)
176 C = 1.0 - cylinder_fractions((nx, ny, nz), R, nx / 2.0, sc.len_to_cells(0.5))
177 s.set_vof(np.asfortranarray(C))
178 s.set_property_model(
"rho",
"linear",
"C", [p[
"rho2"], p[
"rho1"] - p[
"rho2"]])
179 s.set_property_model(
"mu",
"linear",
"C",
180 [sc.mu(p[
"mu2"]), sc.mu(p[
"mu1"] - p[
"mu2"])])
181 s.set_surface_tension(sc.sigma(p[
"sigma"]))
183 s.enable_vof_momentum(p[
"rho2"], p[
"rho1"])
184 s.set_property_model(
"force_z",
"linear",
"C",
185 [-sc.bodyforce(p[
"rho2"] * p[
"g"]),
186 -sc.bodyforce((p[
"rho1"] - p[
"rho2"]) * p[
"g"])])
188 dt = 0.5 * s.capillary_dt()
190 zs = (np.arange(nz) + 0.5) / sc.s
192 vmax, tvmax, yc, t, i = 0.0, 0.0, 0.0, 0.0, 0
196 L = s.vof_step_limits()
197 dt = 0.4 * min(L[
"cfl_dt"], L[
"capillary_dt"])
203 B = 1.0 - s.get_vof()
205 yc = float((B.sum(axis=(0, 1)) * zs).sum() / vb)
206 vrise = float((B * s.get_w()).sum() / vb) / sc.s
208 vmax, tvmax = vrise, t
209 out[label] = (vmax, tvmax, yc)
210 print(f
" {label} v_rise max {vmax:.4f} at t = {tvmax:.3f} y_c(3) = {yc:.4f} "
211 f
"({i} steps, {time.time()-t0:.0f} s)")
213 print(f
"\n published reference (Hysing 2009): v_rise max {p['ref_vmax']:.4f} at "
214 f
"t = {p['ref_tvmax']:.4f}, y_c(3) = {p['ref_yc']:.4f}")
215 a = out[
"staggered (V2b OFF)"]
216 b = out[
"COLLOCATED (V2b n/a)"]
217 print(f
" collocated vs staggered (both V2b off): v_rise {100*(b[0]/a[0]-1):+.2f} %, "
218 f
"y_c(3) {100*(b[2]/a[2]-1):+.2f} %")