1import test from "node:test";
2import assert from "node:assert/strict";
3import { diskMesh, edgeLengths, locate } from "../src/model/mesh.ts";
4import { fixture, maxAbsDiff } from "./helpers.ts";
6test("disk mesh is a valid manifold with good quality", () => {
7 for (const h of [0.03, 0.012]) {
8 const R = 0.2286, m = diskMesh(R, h);
9 let areaSum = 0;
10 for (const a of m.area) { assert.ok(a > 0); areaSum += a; }
11 assert.ok(areaSum > 0.98 * Math.PI * R * R && areaSum <= Math.PI * R * R + 1e-12);
12 const count = new Map<string, number>();
13 for (let e = 0; e < m.e; e++) for (let k = 0; k < 3; k++) {
14 const a = m.tri[3 * e + k], b = m.tri[3 * e + ((k + 1) % 3)];
15 const key = a < b ? `${a}-${b}` : `${b}-${a}`;
16 count.set(key, (count.get(key) ?? 0) + 1);
17 }
18 let n1 = 0;
19 for (const c of count.values()) { assert.ok(c === 1 || c === 2); if (c === 1) n1++; }
20 assert.equal(n1, m.boundary.length);
21 for (const b of m.boundary) assert.ok(Math.abs(Math.hypot(m.xy[2 * b], m.xy[2 * b + 1]) - R) < 1e-12);
22 const L = edgeLengths(m);
23 let qmin = 1, lsum = 0;
24 for (let e = 0; e < m.e; e++) {
25 const a = L[3 * e], b = L[3 * e + 1], c = L[3 * e + 2], s = (a + b + c) / 2;
26 qmin = Math.min(qmin, (8 * (s - a) * (s - b) * (s - c)) / (a * b * c));
27 lsum += a + b + c;
28 }
29 assert.ok(qmin > 0.5, `quality ${qmin}`);
30 const lmean = lsum / L.length;
31 assert.ok(lmean > 0.5 * h && lmean < 1.5 * h);
32 }
33});
35test("mesh matches the Python mesher exactly", () => {
36 const f = fixture.mesh, cfg = fixture.config;
37 const m = diskMesh(cfg.profile.radius, cfg.mesh.element_size, cfg.mesh.smoothing);
38 assert.equal(m.n, f.n_nodes); assert.equal(m.e, f.n_elements); assert.equal(m.boundary.length, f.n_boundary);
39 assert.ok(maxAbsDiff(m.xy.subarray(0, 10), f.xy_first5.flat()) < 1e-12);
40 assert.ok(maxAbsDiff(m.xy.subarray(2 * m.n - 6), f.xy_last3.flat()) < 1e-12);
41 assert.deepEqual(Array.from(m.tri.subarray(0, 15)), f.tri_first5.flat());
42 let areaSum = 0; for (const a of m.area) areaSum += a;
43 assert.ok(Math.abs(areaSum - f.area_sum) < 1e-12);
44 const L = edgeLengths(m);
45 assert.ok(Math.abs(Math.min(...L) - f.min_edge) < 1e-12 && Math.abs(Math.max(...L) - f.max_edge) < 1e-12);
46});
48test("locate returns barycentric weights that sum to one", () => {
49 const m = diskMesh(0.2, 0.03);
50 const { weights } = locate(m, 0.05, -0.07);
51 assert.ok(Math.abs(weights[0] + weights[1] + weights[2] - 1) < 1e-12);
52 assert.throws(() => locate(m, 0.3, 0));
53});