import test from "node:test"; import assert from "node:assert/strict"; import { diskMesh, edgeLengths, locate } from "../src/model/mesh.ts"; import { fixture, maxAbsDiff } from "./helpers.ts"; test("disk mesh is a valid manifold with good quality", () => { for (const h of [0.03, 0.012]) { const R = 0.2286, m = diskMesh(R, h); let areaSum = 0; for (const a of m.area) { assert.ok(a > 0); areaSum += a; } assert.ok(areaSum > 0.98 * Math.PI * R * R && areaSum <= Math.PI * R * R + 1e-12); const count = new Map(); for (let e = 0; e < m.e; e++) for (let k = 0; k < 3; k++) { const a = m.tri[3 * e + k], b = m.tri[3 * e + ((k + 1) % 3)]; const key = a < b ? `${a}-${b}` : `${b}-${a}`; count.set(key, (count.get(key) ?? 0) + 1); } let n1 = 0; for (const c of count.values()) { assert.ok(c === 1 || c === 2); if (c === 1) n1++; } assert.equal(n1, m.boundary.length); for (const b of m.boundary) assert.ok(Math.abs(Math.hypot(m.xy[2 * b], m.xy[2 * b + 1]) - R) < 1e-12); const L = edgeLengths(m); let qmin = 1, lsum = 0; for (let e = 0; e < m.e; e++) { const a = L[3 * e], b = L[3 * e + 1], c = L[3 * e + 2], s = (a + b + c) / 2; qmin = Math.min(qmin, (8 * (s - a) * (s - b) * (s - c)) / (a * b * c)); lsum += a + b + c; } assert.ok(qmin > 0.5, `quality ${qmin}`); const lmean = lsum / L.length; assert.ok(lmean > 0.5 * h && lmean < 1.5 * h); } }); test("mesh matches the Python mesher exactly", () => { const f = fixture.mesh, cfg = fixture.config; const m = diskMesh(cfg.profile.radius, cfg.mesh.element_size, cfg.mesh.smoothing); assert.equal(m.n, f.n_nodes); assert.equal(m.e, f.n_elements); assert.equal(m.boundary.length, f.n_boundary); assert.ok(maxAbsDiff(m.xy.subarray(0, 10), f.xy_first5.flat()) < 1e-12); assert.ok(maxAbsDiff(m.xy.subarray(2 * m.n - 6), f.xy_last3.flat()) < 1e-12); assert.deepEqual(Array.from(m.tri.subarray(0, 15)), f.tri_first5.flat()); let areaSum = 0; for (const a of m.area) areaSum += a; assert.ok(Math.abs(areaSum - f.area_sum) < 1e-12); const L = edgeLengths(m); assert.ok(Math.abs(Math.min(...L) - f.min_edge) < 1e-12 && Math.abs(Math.max(...L) - f.max_edge) < 1e-12); }); test("locate returns barycentric weights that sum to one", () => { const m = diskMesh(0.2, 0.03); const { weights } = locate(m, 0.05, -0.07); assert.ok(Math.abs(weights[0] + weights[1] + weights[2] - 1) < 1e-12); assert.throws(() => locate(m, 0.3, 0)); });