56def run(n, ratio, ja, x0p=0.10, xep=0.25, alpha_l=1.0, cfl=0.2, fo=0.5, nt=4,
57 kratio=None, rcpratio=None, consistent=True, plane=True, quad=False, muscl=False,
58 verbose=True, energy_order=1, deposit=None):
59 """One resolution. The PHYSICAL problem is fixed (domain length 1, alpha_l = 1, the vapour
60 layer growing from x0p to xep of the domain) and only h = 1/n changes. `nt` is the transverse
61 extent: the problem is 1-D so 4 is enough physically, but it decides how far the pressure
62 multigrid can coarsen (see the findings)."""
66 t0 = (x0p / (2 * b)) ** 2 / alpha_l
67 te = (xep / (2 * b)) ** 2 / alpha_l
71 rho_l, rho_v = 1.0, rr
73 k_l = al * rho_l * cpl
75 rcp_v = rcp_l / (rcpratio
if rcpratio
else ratio)
76 k_v = k_l / (kratio
if kratio
else ratio)
78 h_lv = rho_l * cpl * dT / (rho_v * ja)
81 s = pf.Solver(n, ny, nz)
84 s.set_domain_bc(
"-x",
"wall")
85 s.set_domain_bc(
"+x",
"outflow")
86 s.set_pressure_geometry(np.full((n, ny, nz), 1.0, order=
"F"))
88 c = np.zeros((n, ny, nz), order=
"F")
90 c[i, :, :] = min(1.0, max(0.0, (i + 1) - X0))
92 s.set_property_model(
"rho",
"linear",
"C", [rho_v, rho_l - rho_v])
93 s.set_pressure_fcg(
True, 4000, 1e-10)
96 t = np.zeros((n, ny, nz), order=
"F")
100 sv = x / (2 * math.sqrt(alpha_l * t0)) - b * (1.0 - rr)
101 t[i, :, :] = dT - dT * math.erfc(sv) / math.erfc(b * rr)
109 sv = 1.0 / (2 * math.sqrt(alpha_l * tt)) - b * (1.0 - rr)
110 return dT - dT * math.erfc(sv) / math.erfc(b * rr)
112 s.add_scalar(
"T", al,
"koren", 60)
113 s.set_scalar_bc(
"T",
"-x",
"dirichlet", 0.0)
114 s.set_scalar_bc(
"T",
"+x",
"dirichlet", farT(t0))
116 s.enable_phase_change(rho_v, rho_l, h_lv)
117 s.set_phase_change_thermal(
True,
"T", 0.0, k_v, k_l, 0.0)
118 s.diagnostics.set_phase_change_plane_dirichlet(plane)
119 s.diagnostics.set_phase_change_quadratic_fit(quad)
121 s.set_phase_change_energy(
True, rcp_v, rcp_l)
122 s.diagnostics.set_phase_change_energy_muscl(muscl)
124 if energy_order != 1:
125 s.diagnostics.set_phase_change_energy_order(energy_order)
126 if deposit
is not None:
127 s.diagnostics.set_phase_change_deposit_fallback(bool(deposit))
130 Xdot = b * math.sqrt(alpha_l / t0) * n
131 ul = Xdot * (1.0 - rr)
132 u = np.zeros((n, ny, nz), order=
"F")
133 u[int(X0) + 2:, :, :] = ul
139 tcur, nsteps, itmax, capped = t0, 0, 0, 0
141 Xd = b * math.sqrt(alpha_l / tcur) * n
142 dt = min(cfl / max(Xd * (1.0 - rr), 1e-30), fo / al)
143 dt = min(dt, (te - tcur))
145 s.set_scalar_bc(
"T",
"+x",
"dirichlet", farT(tcur + dt))
149 it = s.diagnostics.last_pressure_iterations()
150 itmax = max(itmax, it)
153 layer = n - s.get_vof().sum() / (ny * nz)
154 exact = 2 * b * math.sqrt(alpha_l * te) * n
155 d = s.diagnostics.phase_change_diagnostics()
157 tnum = s.get_field(
"T")[:, 0, 0]
161 xg = 2 * b * math.sqrt(alpha_l * te)
163 sv = x / (2 * math.sqrt(alpha_l * te)) - b * (1.0 - rr)
164 ex = dT - dT * math.erfc(sv) / math.erfc(b * rr)
165 terr = max(terr, abs(tnum[i] - ex))
168 print(f
" N = {n:4d} steps {nsteps:5d} b {b:.6f} layer {layer:9.5f} cells "
169 f
"(exact {exact:9.5f}) rel {100*(layer-exact)/exact:+8.4f} %")
170 print(f
" |T - T_exact|_inf over the liquid = {terr:.4e} ({100*terr/dT:.3f} % of "
171 f
"dT, {tn} cells) C in [{d['min_C']:.2e}, {d['max_C']:.6f}]")
172 print(f
" pressure iters max {itmax}/4000 (capped steps {capped}), "
173 f
"band_div {d['band_div']:.3e}, T in [{d['T_min']:.4e}, {d['T_max']:.6f}], "
174 f
"unresolved {d['unresolved']:.1e}, fallback {d['fallback_cells']}")
175 return abs((layer - exact) / exact), terr / dT, capped, itmax
179 ap = argparse.ArgumentParser()
180 ap.add_argument(
"--ratio", type=float, default=10.0)
181 ap.add_argument(
"--ja", type=float, default=1.0)
182 ap.add_argument(
"--ns", type=str, default=
"64,128,256")
183 ap.add_argument(
"--kratio", type=float, default=
None)
184 ap.add_argument(
"--rcpratio", type=float, default=
None)
185 ap.add_argument(
"--no-consistent", action=
"store_true")
186 ap.add_argument(
"--no-plane", action=
"store_true")
187 ap.add_argument(
"--no-quad", action=
"store_true")
188 ap.add_argument(
"--fo", type=float, default=0.5)
189 ap.add_argument(
"--muscl", action=
"store_true")
190 ap.add_argument(
"--nt", type=int, default=4)
191 ap.add_argument(
"--energy-order", type=int, default=1,
192 help=
"WO-P3g: 2 = the second-order interfacial energy operator")
193 ap.add_argument(
"--deposit-fallback", type=int, default=
None,
194 help=
"WO-P3f open item 6: the 5^3 divergence-source deposit fallback")
196 ns = [int(x)
for x
in a.ns.split(
",")]
197 print(f
"P2 sucking interface: rho_l/rho_v = {a.ratio:g}, Ja = {a.ja:g}, "
198 f
"k ratio {a.kratio or a.ratio:g}, rho*c_p ratio {a.rcpratio or a.ratio:g}, "
199 f
"consistent energy {not a.no_consistent}, plane Dirichlet {not a.no_plane}, "
200 f
"quadratic fit {not a.no_quad}, Fo {a.fo:g}, WO-P3g energy order {a.energy_order}, "
201 f
"deposit fallback {a.deposit_fallback}")
204 e, te_, capped, itmax =
run(n, a.ratio, a.ja, kratio=a.kratio, rcpratio=a.rcpratio,
205 consistent=
not a.no_consistent, plane=
not a.no_plane,
206 quad=
not a.no_quad, fo=a.fo, muscl=a.muscl, nt=a.nt,
207 energy_order=a.energy_order, deposit=a.deposit_fallback)
211 print(f
" *** {capped} CAPPED pressure solves at N = {n}: rule 3b, run INVALID")
212 for x, y, na, nb
in zip(errs[:-1], errs[1:], ns[:-1], ns[1:]):
213 print(f
" observed order {na} -> {nb}: {math.log2(x/y):.3f}")
215 print(f
" observed order {ns[0]} -> {ns[-1]} (fit): "
216 f
"{math.log2(errs[0]/errs[-1])/math.log2(ns[-1]/ns[0]):.3f}")
217 print(f
" GATE: order >= 1.4 and |T - T_exact| <= 1 % of dT at N = {ns[-1]} "
218 f
"(got {100*terrs[-1]:.3f} %)")
run(n, ratio, ja, x0p=0.10, xep=0.25, alpha_l=1.0, cfl=0.2, fo=0.5, nt=4, kratio=None, rcpratio=None, consistent=True, plane=True, quad=False, muscl=False, verbose=True, energy_order=1, deposit=None)