flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_velocity_solver_variable_mu.py
Go to the documentation of this file.
1#!/usr/bin/env python
2"""The momentum solver never silently drops a variable viscosity.
3
4The velocity multigrid takes a SCALAR mu. Combined with a variable viscosity (a 'mu' closure or
5set_property_mode('variable')) it used to solve with the constant set_mu value instead: on a
6mirror-pair case the explicit multigrid with mu(T) differed from its own constant-mu run by only
72e-4 and from the red-black smoother by 50-70 %. Now:
8
9 1. an EXPLICIT set_velocity_solver('multigrid') / set_velocity_multigrid(True) raises ValueError
10 with a variable viscosity, in either order (solver first, then the closure / the mode; or
11 the other way round), and names the cause;
12 2. the AUTO rule (which picks the V-cycle once kappa = 1 + 4 dt mu sum(w) / rho >= 13) keeps a
13 variable viscosity on the red-black smoother -- velocity_multigrid_active() is False after
14 the first step, while the same case at constant mu takes the V-cycle -- and the variable-mu
15 result equals the explicit 'gauss_seidel' run bitwise.
16
17Run: OMP_NUM_THREADS=4 PYTHONPATH=<build> python tests/python/test_velocity_solver_variable_mu.py
18Exit 0 pass, 1 fail, 77 skipped (no module).
19"""
20import sys
21
22import numpy as np
23
24try:
25 import peclet.flow as pf
26except ImportError:
27 print("SKIP: peclet.flow not importable")
28 sys.exit(77)
29
30N = 16
31
32
33def make(variable_mu, solver=None, dt=2.0):
34 """Walled box, a transported scalar T driving the body force (and mu(T) when variable_mu).
35 dt = 2, mu = 0.5: kappa = 1 + 12 * 1.0 = 13 -> AUTO picks the V-cycle at constant mu."""
36 s = pf.Solver(N, N, N)
37 s.set_rho(1.0)
38 s.set_mu(0.5)
39 s.set_dt(dt)
40 s.set_domain_bc("-y", "wall", (0, 0, 0))
41 s.set_domain_bc("+y", "wall", (0, 0, 0))
42 s.set_pressure_geometry(np.full((N, N, N), 10.0, order="F"))
43 s.add_scalar("T", 0.0, "koren")
44 X, Y, Z = np.meshgrid(*(np.arange(N) + 0.5,) * 3, indexing="ij")
45 s.set_field("T", np.asfortranarray(np.exp(-((X - 8) ** 2 + (Y - 5) ** 2 + (Z - 8) ** 2) / 8)))
46 if solver:
47 s.diagnostics.set_velocity_solver(solver)
48 if variable_mu:
49 s.set_property_model("mu", "linear", "T", [0.5, -0.4])
50 s.set_property_model("force_x", "linear", "T", [0.0, -0.02])
51 return s
52
53
54def raises(fn):
55 try:
56 fn()
57 except ValueError as e:
58 return "scalar viscosity" in str(e).lower() or "SCALAR viscosity" in str(e)
59 return False
60
61
62def main():
63 ok = True
64
65 def check(name, good):
66 nonlocal ok
67 ok &= bool(good)
68 print(f"{name:66s} {'ok' if good else 'FAIL'}")
69
70 # 1. explicit multigrid + variable viscosity: refused in every order
71 def closure_then_solver():
72 s = make(True)
73 s.diagnostics.set_velocity_solver("multigrid")
74
75 def solver_then_closure():
76 make(True, solver="multigrid")
77
78 def solver_then_mode():
79 s = make(False, solver="multigrid")
80 s.diagnostics.set_property_mode("variable")
81
82 def closure_then_raw_setter():
83 s = make(True)
84 s.set_velocity_multigrid(True)
85
86 check("explicit: mu closure, then set_velocity_solver('multigrid')", raises(closure_then_solver))
87 check("explicit: set_velocity_solver('multigrid'), then mu closure", raises(solver_then_closure))
88 check("explicit: set_velocity_solver('multigrid'), then property mode", raises(solver_then_mode))
89 check("explicit: mu closure, then set_velocity_multigrid(True)", raises(closure_then_raw_setter))
90 s = make(False, solver="multigrid") # constant mu: the explicit V-cycle stays legal
91 s.step()
92 check("explicit multigrid at constant mu still runs", s.diagnostics.velocity_multigrid_active())
93
94 # 2. AUTO: the V-cycle at constant mu, the smoother under a variable mu, bitwise == explicit GS
95 c = make(False)
96 c.step()
97 check("AUTO, constant mu, kappa 13: V-cycle", c.diagnostics.velocity_multigrid_active())
98 a, g = make(True), make(True, solver="gauss_seidel")
99 for _ in range(3):
100 a.step()
101 g.step()
102 check("AUTO, variable mu: red-black smoother", not a.diagnostics.velocity_multigrid_active())
103 same = all(np.array_equal(x, y) for x, y in
104 ((a.get_u(), g.get_u()), (a.get_v(), g.get_v()), (a.get_w(), g.get_w()),
105 (a.get_p(), g.get_p())))
106 check("AUTO, variable mu == explicit gauss_seidel, bitwise (3 steps)", same)
107 print("PASS" if ok else "FAIL")
108 return 0 if ok else 1
109
110
111if __name__ == "__main__":
112 sys.exit(main())