"""D2Q9 equilibrium helpers — compute_feq_d2q9 and compute_macro_from_ddf correctness.

No GPU required."""

import unittest

import numpy as np

from CelerisLab.lbm.equilibrium import compute_feq_d2q9, compute_macro_from_ddf


class TestEquilibrium(unittest.TestCase):
    """Verify D2Q9 equilibrium and macroscopic helpers."""

    def test_feq_at_rest(self):
        """Equilibrium at rho=1.0, u=0 should give w_i (weights)."""
        feq = compute_feq_d2q9(1.0, 0.0, 0.0)
        w = np.array([4/9, 1/9, 1/9, 1/9, 1/9,
                      1/36, 1/36, 1/36, 1/36], dtype=np.float32)
        np.testing.assert_allclose(feq, w, rtol=1e-6)

    def test_feq_sums_to_rho(self):
        """Sum of feq should equal rho."""
        rho, ux, uy = 1.2, 0.05, -0.02
        feq = compute_feq_d2q9(rho, ux, uy)
        self.assertAlmostEqual(float(np.sum(feq)), rho, places=6)

    def test_macro_preserves_ux_uy(self):
        """compute_macro_from_ddf(feq) should recover rho, ux, uy."""
        rho, ux, uy = 1.0, 0.1, 0.0
        feq = compute_feq_d2q9(rho, ux, uy)
        rho_out, ux_out, uy_out = compute_macro_from_ddf(feq)
        self.assertAlmostEqual(rho_out, rho, places=6)
        self.assertAlmostEqual(ux_out, ux, places=6)
        self.assertAlmostEqual(uy_out, uy, places=6)

    def test_feq_nonzero_vel(self):
        """Equilibrium at non-zero velocity should be asymmetric."""
        feq_x = compute_feq_d2q9(1.0, 0.1, 0.0)
        feq_y = compute_feq_d2q9(1.0, 0.0, 0.1)
        # x-directed flow should have f1 > f2 (right > left)
        self.assertGreater(feq_x[1], feq_x[2],
                           "Right-moving f1 should exceed left-moving f2")
        # y-directed flow should have f3 > f4 (up > down)
        self.assertGreater(feq_y[3], feq_y[4],
                           "Up-moving f3 should exceed down-moving f4")


if __name__ == "__main__":
    unittest.main()
