flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
dvd_cavity.py
Go to the documentation of this file.
1#!/usr/bin/env python
2"""Differentially heated square cavity (de Vahl Davis 1983) — validates the Boussinesq
3field->momentum coupling (property closures + per-cell body force + scalar transport).
4
5Left wall hot T=1, right wall cold T=0, top/bottom adiabatic, no-slip everywhere, gravity in -y
6with a Boussinesq buoyancy body force. Benchmark average Nusselt number on the hot wall:
7
8 Ra Nu_avg u_max* v_max*
9 1e3 1.118 3.649 3.697
10 1e4 2.243 16.178 19.617
11 1e5 4.519 34.73 68.59
12
13(* velocity extrema normalised by alpha/L.) Run: PYTHONPATH=<build> python dvd_cavity.py
14"""
15import numpy as np, time
16import peclet.flow as F
17
18REF = {1e3: 2.243} # (Nu ref filled per-Ra below)
19NU_REF = {1e3: 1.118, 1e4: 2.243, 1e5: 4.519}
20
21
22def cavity(N, Ra, Pr=0.71, mu=0.05, dt=8.0, steps=3000, tol=1e-5, verbose=False):
23 nz = 4
24 s = F.Solver(N, N, nz)
25 s.set_rho(1.0); s.set_mu(mu); s.set_dt(dt)
26 s.set_implicit_advection(True); s.set_outer_iterations(2)
27 for f in (0, 1, 2, 3):
28 s.set_domain_bc(f, 1, 0.0, 0.0, 0.0) # no-slip walls (z periodic)
29 s.set_pressure_geometry(np.asfortranarray(np.full((N, N, nz), 10.0)))
30 alpha = mu / Pr
31 s.add_scalar("T", diffusivity=alpha, scheme=1, iters=50)
32 s.set_scalar_bc("T", 0, 2, 1.0); s.set_scalar_bc("T", 1, 2, 0.0) # hot / cold walls
33 s.set_scalar_bc("T", 2, 1, 0.0); s.set_scalar_bc("T", 3, 1, 0.0) # adiabatic top/bottom
34 coeff = Ra * mu * mu / (Pr * N**3) # rho0*g*beta so that Ra hits target
35 s.set_property_model("force_y", "boussinesq", "T", [1.0, coeff, 1.0, 0.5])
36 x = np.arange(N)
37 T0 = np.repeat((1.0 - (x + 0.5) / N)[:, None, None], N, 1).repeat(nz, 2)
38 s.set_field("T", np.asfortranarray(T0.astype(np.float64)))
39 t0 = time.time(); prev = None
40 for it in range(steps):
41 s.step()
42 if it % 100 == 99:
43 u = s.get_u(); um = np.abs(u).max()
44 if prev is not None and np.abs(u - prev).max() / (um + 1e-30) < tol:
45 break
46 prev = u.copy()
47 T = s.get_field("T")
48 Nu = 2.0 * N * (1.0 - T[0, :, :].mean()) # avg -dT/dx * L on the hot wall
49 u, v = s.get_u(), s.get_v()
50 return dict(Nu=Nu, umax=np.abs(u).max() * N / alpha, vmax=np.abs(v).max() * N / alpha,
51 it=it + 1, t=time.time() - t0)
52
53
54if __name__ == "__main__":
55 for N, Ra in [(24, 0.0), (32, 1e4)]:
56 r = cavity(N, Ra)
57 if Ra == 0.0:
58 print(f"conduction (Ra=0) N={N}: Nu={r['Nu']:.4f} (expect 1.0)")
59 else:
60 e = abs(r['Nu'] - NU_REF[Ra]) / NU_REF[Ra] * 100
61 print(f"Ra={Ra:.0e} N={N}: Nu={r['Nu']:.3f} (ref {NU_REF[Ra]}, err {e:.1f}%) "
62 f"u*={r['umax']:.1f} v*={r['vmax']:.1f} [{r['it']} steps, {r['t']:.0f}s]")
cavity(N, Ra, Pr=0.71, mu=0.05, dt=8.0, steps=3000, tol=1e-5, verbose=False)
Definition dvd_cavity.py:22