// Run a numbl script with the bp_* helpers on its path, and turn its `sys` // struct into a BeadSystem. Shared by the browser worker and the tests. import { executeCode, RTV } from "numbl"; import { parseSystem } from "./parse"; import { relax } from "./relax"; import type { SymEig } from "./modes"; import type { BeadSystem } from "./types"; export interface HelperFile { name: string; source: string; } export function runScript( source: string, helpers: HelperFile[], onOutput: (text: string) => void ): { sys: BeadSystem; warnings: string[] } { const result = executeCode(source, { onOutput, displayResults: true }, helpers, "script.m"); return parseSystem(result.variableValues.sys); } // Steps that change the system before it is simulated (now: static relaxation // under the load). Returns notes for the run report. export function prepareSystem(sys: BeadSystem): string[] { const notes: string[] = []; if (sys.relax) { const r = relax(sys); let sag = 0; for (let q = 0; q < r.pos.length; q++) sag = Math.max(sag, Math.abs(r.pos[q] - sys.pos0[q])); sys.pos0 = r.pos; notes.push( `Relaxed to equilibrium in ${r.iterations} iterations (largest net force ${r.residual.toExponential(1)} N; beads moved up to ${(sag * 1000).toPrecision(3)} mm).` ); } return notes; } // Symmetric eigendecomposition through numbl's eig. export const numblEig: SymEig = (A, n) => { const r = executeCode("[V, D] = eig(A); d = diag(D);", { initialVariableValues: { A: RTV.tensor(A, [n, n]) }, }); const V = r.variableValues.V as unknown as { data: Float64Array }; const d = r.variableValues.d as unknown as { data: Float64Array } | number; const values = typeof d === "number" ? Float64Array.of(d) : d.data; return { values, vectors: V.data ?? Float64Array.of(1) }; };