1/**
2 * The seeded perturbation a model's `init` starts from.
3 *
4 * Host-side rather than in the .m, so a run is reproducible from an integer
5 * seed and the same field can be handed to any model.
6 */
8/** Seeded normal deviates: mulberry32 + Box-Muller. */
9export function makeRandn(seed: number): () => number {
10 let s = seed >>> 0;
11 const rand = (): number => {
12 s = (s + 0x6d2b79f5) >>> 0;
13 let t = s;
14 t = Math.imul(t ^ (t >>> 15), t | 1);
15 t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
16 return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
17 };
18 let spare: number | null = null;
19 return () => {
20 if (spare !== null) {
21 const v = spare;
22 spare = null;
23 return v;
24 }
25 let u = 0;
26 while (u === 0) u = rand();
27 const r = Math.sqrt(-2 * Math.log(u));
28 const th = 2 * Math.PI * rand();
29 spare = r * Math.sin(th);
30 return r * Math.cos(th);
31 };
32}
34/** `amp`-scaled normal deviates, one per grid point, in index order. */
35export function seededNoise(npts: number, amp: number, seed: number): Float32Array {
36 const randn = makeRandn(seed);
37 const out = new Float32Array(npts);
38 for (let i = 0; i < npts; i++) out[i] = amp * randn();
39 return out;
40}