/ concept-collection / turing-surface-cache
Sign in
concept-collection / turing-surface-cache
turing-surface-cache / src / cache / options.ts
96 lines · 3.7 KBBlameHistoryRaw
1/**
2 * The discrete parameter space.
3 *
4 * Every knob the app offers is a choice from a short enumerated list, so a run
5 * is fully identified by a small tuple of exact values — which is what makes
6 * the cloud cache work: the same choices always produce the same cache key
7 * (src/cache/spec.ts), with no floating-point formatting ambiguity, because
8 * the values *are* these list entries, never something typed or interpolated.
9 *
10 * The numerical-scheme knobs (lmax, niter, seed wavelength) are fixed in this
11 * version rather than offered, but they are recorded in the spec and the cache
12 * key all the same, so making them choices later invalidates nothing.
13 */
14import type { Params } from '../mgpu/registry.ts';
16export interface DiscreteChoice {
17 key: string;
18 label: string;
19 /** The allowed values, in display order. */
20 values: number[];
21 /** Default — must be one of `values`. */
22 value: number;
25/** The model offered first, and what Reset returns to. */
26export const DEFAULT_MODEL_KEY = 'schnakenberg';
28/** Model parameter choices, by model key. Every dt divides every end time. */
29export const MODEL_CHOICES: Record<string, DiscreteChoice[]> = {
30 schnakenberg: [
31 { key: 'a', label: 'a', values: [0.05, 0.1, 0.15, 0.2], value: 0.1 },
32 { key: 'b', label: 'b', values: [0.7, 0.9, 1.1, 1.3], value: 0.9 },
33 { key: 'D1', label: 'D₁', values: [1.6e-4, 4e-4, 1e-3], value: 4e-4 },
34 { key: 'D2', label: 'D₂', values: [3.2e-3, 8e-3, 2e-2], value: 8e-3 },
35 { key: 'dt', label: 'dt', values: [0.02, 0.05, 0.1], value: 0.05 },
36 ],
37 brusselator: [
38 { key: 'A', label: 'A', values: [2, 3, 4], value: 3 },
39 { key: 'B', label: 'B', values: [7, 9, 11], value: 9 },
40 { key: 'D1', label: 'D₁', values: [1.7e-3, 3.33e-3, 6.7e-3], value: 3.33e-3 },
41 { key: 'D2', label: 'D₂', values: [8.3e-3, 1.67e-2, 3.3e-2], value: 1.67e-2 },
42 { key: 'dt', label: 'dt', values: [0.01, 0.02, 0.05], value: 0.02 },
43 ],
44 allencahn: [
45 { key: 'eps2', label: 'ε²', values: [5e-4, 1e-3, 2e-3], value: 1e-3 },
46 { key: 'dt', label: 'dt', values: [0.01, 0.02, 0.05], value: 0.02 },
47 ],
48};
50/** Geometry parameter choices, by geometry key. The sphere has none. */
51export const GEOMETRY_CHOICES: Record<string, DiscreteChoice[]> = {
52 sphere: [],
53 ellipsoid: [
54 { key: 'ax', label: 'a', values: [0.6, 1, 1.5], value: 1.5 },
55 { key: 'ay', label: 'b', values: [0.6, 1, 1.5], value: 1 },
56 { key: 'az', label: 'c', values: [0.6, 1, 1.5], value: 0.6 },
57 ],
58 peanut: [
59 { key: 'waist', label: 'waist', values: [0.4, 0.6, 0.8], value: 0.6 },
60 { key: 'stretch', label: 'stretch', values: [0, 0.6, 1.2], value: 0.6 },
61 ],
62};
64export const SEED_CHOICE: DiscreteChoice = {
65 key: 'seed',
66 label: 'seed',
67 values: [1, 2, 3, 4, 5],
68 value: 1,
69};
71/**
72 * End times, in simulation-time units. Every entry is an exact multiple of
73 * every dt choice, so a run to any of them lands on a whole number of steps —
74 * and a run to a later one passes exactly through the earlier ones. That is
75 * where the along-the-way cache snapshots come from, and, in the other
76 * direction, why a computation can warm-start from the longest cached
77 * shorter run of the same spec.
78 */
79export const T_END_CHOICE: DiscreteChoice = {
80 key: 'tEnd',
81 label: 'end time',
82 values: [100, 200, 400, 800, 1600],
83 value: 100,
84};
86/** Fixed numerical-scheme settings (recorded in every spec and cache key). */
87export const LMAX = 63;
88export const NITER = 8;
89export const LAM3 = 0.5;
91export const defaultChoiceParams = (choices: DiscreteChoice[]): Params =>
92 Object.fromEntries(choices.map((c) => [c.key, c.value]));
94/** Display formatting: exact and compact ("4e-4", "0.05"). */
95export const fmtChoice = (v: number): string =>
96 v !== 0 && Math.abs(v) < 0.01 ? v.toExponential() : String(v);
moveopenescclose