/ concept-collection / turing-sphere
concept-collection / turing-sphere
57 lines · 1.9 KBBlameHistoryRaw
1/**
2 * Long-run sanity check: run Schnakenberg to t = 100 on desktop WebGPU and
3 * confirm the pattern saturates into O(1)-contrast spots rather than decaying or
4 * blowing up. Short runs cannot tell a growing instability from a diverging one.
5 *
6 * vite-node scripts/longrun-node.ts [lmax]
7 */
8import { requestShtDevice } from '../src/sht/sht.ts';
9import { ModelSession } from '../src/mgpu/session.ts';
10import { mModelByKey, defaultParams } from '../src/mgpu/registry.ts';
11import { installWebGpu, errMsg, NO_ADAPTER_HINT } from './nodeWebGpu.ts';
13const lmax = Number(process.argv[2] ?? 31);
14const model = mModelByKey('schnakenberg')!;
15const params = defaultParams(model);
17const runtime = await installWebGpu();
18const device = await requestShtDevice().catch((e: unknown) => {
19 throw new Error(`${errMsg(e)}\n${NO_ADAPTER_HINT}`);
20});
21const session = await ModelSession.create({ device, model, params, lmax });
22session.seed(1);
23console.log(`longrun — models/${model.key}.m at lmax ${lmax}, ${runtime}\n`);
25const nsteps = Math.round(100 / params.dt);
26const BATCH = 50;
27const t0 = performance.now();
28let lo = 0;
29let hi = 0;
30for (let s = 0; s < nsteps; s += BATCH) {
31 session.step(Math.min(BATCH, nsteps - s));
32 const u = await session.read(model.species[0]);
33 lo = Infinity;
34 hi = -Infinity;
35 for (const v of u) {
36 if (v < lo) lo = v;
37 if (v > hi) hi = v;
38 }
39 if (session.steps % 400 === 0) {
40 console.log(
41 `t=${session.t.toFixed(1).padStart(5)} u in [${lo.toFixed(4)}, ${hi.toFixed(4)}] ` +
42 `contrast ${(hi - lo).toFixed(4)}`,
43 );
44 }
46const ms = (performance.now() - t0) / nsteps;
48const contrast = hi - lo;
49const saturated = Number.isFinite(contrast) && contrast > 0.5 && hi < 10;
50console.log(
51 `\n${saturated ? 'PASS' : 'FAIL'} pattern saturated: contrast ${contrast.toFixed(4)} ` +
52 `after ${session.steps} steps (${ms.toFixed(1)} ms/step)`,
53);
55session.destroy();
56device.destroy();
57process.exit(saturated ? 0 : 1);