Files
CelerisLab/tests/unit/test_jet_circle_cv.py
T

140 lines
5.1 KiB
Python

"""CPU-only science, geometry, units, and source tests; no PyCUDA import."""
import sys
from pathlib import Path
import unittest
import numpy as np
ROOT = Path(__file__).resolve().parents[2]
REPO = ROOT
sys.path.insert(0, str(ROOT / "tests/validation"))
sys.path.insert(0, str(REPO / "src"))
from run_jet_circle_cv import (
CX,
CY,
W,
case,
state,
cv,
aperture_probe,
measured_aperture_flux,
verify,
)
def eq(rho, u, v):
cu = CX[:, None, None] * u + CY[:, None, None] * v
return W[:, None, None] * rho * (1 + 3 * cu + 4.5 * cu**2 - 1.5 * (u * u + v * v))
class Host(unittest.TestCase):
def test_descriptor_and_uniform_closed_flux(self):
from CelerisLab.lbm.descriptors import D2Q9_EX, D2Q9_EY
np.testing.assert_array_equal(CX, D2Q9_EX)
np.testing.assert_array_equal(CY, D2Q9_EY)
rho = np.full((48, 64), 1.01)
g = eq(rho, 0.023, -0.017)
inventory, flux = cv(g, np.ones((48, 64), bool), (0, 0), (5, 4, 25, 20), 0.0072)
np.testing.assert_allclose(
inventory, 320 * 1.01 * np.array([1, 0.023, -0.017]), atol=1e-12
)
np.testing.assert_allclose(flux, 0, atol=1e-14)
def test_affine_velocity_independent_divergence(self):
y, x = np.mgrid[:48, :64]
x = (x + 0.5) * 0.5
y = (y + 0.5) * 0.5
a = 0.001
g = eq(np.ones_like(x), a * x, -a * y)
_, flux = cv(g, np.ones(x.shape, bool), (0, 0), (5, 4, 25, 20), 0.0072)
np.testing.assert_allclose(
flux, [0, a * a * 320 * 15, a * a * 320 * 12], atol=1e-13
)
def test_quadratic_viscous_flux_sign_and_units(self):
y, x = np.mgrid[:48, :64]
y = (y + 0.5) * 0.5
a = 0.0001
nu = 0.0072
g = eq(np.ones_like(y), a * y * y, np.zeros_like(y))
_, flux = cv(g, np.ones(y.shape, bool), (0, 0), (5, 4, 25, 20), nu)
np.testing.assert_allclose(flux, [0, -2 * nu * a * 320, 0], atol=2e-14)
def test_geometry_adapter_match_and_apertures(self):
from CelerisLab.config import LBMConfig
from CelerisLab.body.geometry.circle import CircleGeometry
from CelerisLab.body.objects import SimObject
from CelerisLab.body.jets import Jet, Sector, Radial, jet_link_shapes
from CelerisLab.lbm.refinement import FixedPatch2D, prepare_fine_boundary
from CelerisLab.lbm.descriptors import SOLID
c = case()
center = np.array(c["center"])
r = c["diameter"] / 2
cfg = LBMConfig(nx=c["nx"], ny=c["ny"], viscosity=c["nu"])
cfg.validate()
patch = FixedPatch2D.from_config(cfg, c["bounds"])
obj = SimObject(0, CircleGeometry(*center, r), center=tuple(center), radius=r)
jets = [
Jet(
Sector(tuple(center), a, np.pi / 12, r + 0.1),
Radial(tuple(center), inward=False),
"uniform",
s * c["jet_speed"],
)
for a, s in [(np.pi / 2, 1), (3 * np.pi / 2, -1)]
]
host = prepare_fine_boundary(cfg, patch, [obj], jets=jets)
shape, ids = jet_link_shapes(jets, host.curved_hits)
self.assertTrue((ids == 0).any() and (ids == 1).any() and (ids < 0).any())
self.assertGreater(host.curved_host[2].min(), 0.010001)
self.assertFalse(np.any(host.curved_host[-1]))
links = CircleGeometry(*(2 * center - 0.5), 2 * r).build_cut_links(
2 * c["nx"], 2 * c["ny"]
)
np.testing.assert_array_equal([v.dir for v in links], host.curved_host[1])
np.testing.assert_allclose(
[v.q for v in links], host.curved_host[2], atol=2e-7, rtol=0
)
np.testing.assert_allclose(
np.array([[v.hit_x, v.hit_y] for v in links]) * 0.5 + 0.25,
host.curved_hits,
atol=2e-12,
)
fluid = (host.flags.reshape(patch.fine_shape) & SOLID) == 0
g = state((9, *patch.fine_shape), c["u"])
g[:, ~fluid] = np.nan
for contour in c["contours"]:
cv(g, fluid, patch.fine_origin, contour, c["nu"])
probe = aperture_probe(fluid, patch.fine_origin, center, r)
measured = measured_aperture_flux(g, probe)
np.testing.assert_allclose(
measured, 0, atol=1e-14
) # x-directed flow has zero flux on symmetric top/bottom arcs
print(
"GEOMETRY",
dict(
links=len(links),
aperture_counts=[int((ids == i).sum()) for i in [0, 1]],
q_min=float(host.curved_host[2].min()),
q_max=float(host.curved_host[2].max()),
fallbacks=int(np.count_nonzero(host.curved_host[-1])),
sample_distances=[p[-1] for p in probe],
),
)
def test_diffusive_scaling(self):
a, b = case(1), case(2)
self.assertEqual(a["re_d"], b["re_d"])
self.assertEqual(a["nu"], b["nu"])
self.assertEqual(a["final_t_star"], b["final_t_star"])
self.assertEqual(a["steps"] * 4, b["steps"])
def test_source_pin(self):
verify(REPO)
if __name__ == "__main__":
unittest.main()