"""Mesh volume by the divergence theorem (exact for the mesh), NumPy and numba, on the 12 meshes; against
the descriptor's volume (out/volume.csv). out/volume_sota.csv."""
import sys
sys.argv = [sys.argv[0], "x"]
from hull import OBJECTS, OUT, timeit  # noqa: E402
import numba, numpy as np, pandas as pd, trimesh  # noqa: E402


@numba.njit(cache=True)
def vol_nb(V, F):
    s = 0.0
    for f in range(F.shape[0]):
        a, b, c = V[F[f, 0]], V[F[f, 1]], V[F[f, 2]]
        s += a[0] * (b[1] * c[2] - b[2] * c[1]) - a[1] * (b[0] * c[2] - b[2] * c[0]) + a[2] * (b[0] * c[1] - b[1] * c[0])
    return s / 6


def vol_np(V, F):
    a, b, c = V[F[:, 0]], V[F[:, 1]], V[F[:, 2]]
    return np.einsum("ij,ij->", a, np.cross(b, c)) / 6


rows = []
fc = pd.read_csv(OUT / "volume.csv")
for name, path in OBJECTS.items():
    m = trimesh.load(path, force="mesh")
    V, F = np.ascontiguousarray(m.vertices, np.float64), np.ascontiguousarray(m.faces, np.int64)
    r = dict(obj=name, faces=len(F), vol_rel=vol_nb(V, F) / m.volume)
    r["np_ms"] = timeit(lambda: vol_np(V, F))
    r["nb_ms"] = timeit(lambda: vol_nb(V, F))
    g = fc[(fc.obj == name) & (fc.layers == 128) & (fc.atoms_req == 6144)].iloc[0]
    r["fcp_ms"], r["fcp_err_pct"] = g.ms_s1, 100 * (g.vol_s1 - 1)
    rows.append(r)
d = pd.DataFrame(rows)
d.to_csv(OUT / "volume_sota.csv", index=False)
print(d.round(4).to_string())
