/ concept-collection / turing-surface
Sign in
concept-collection / turing-surface
136 lines · 4.5 KBBlameHistoryRaw
1/**
2 * The available models: their MATLAB source, and the metadata the host owns.
3 *
4 * A model's *algorithm* lives in its .m file. Everything around it lives here:
5 * the parameter names the .m may take as arguments, their defaults and slider
6 * ranges, which grid fields to render, and the dealiasing degree. The .m
7 * declares nothing about these — it just names the parameters it wants, and
8 * `CompiledModel` matches each against this table.
9 *
10 * Naming convention, documented in each .m:
11 * `u`, `v`, ... grid fields the model computes and the app renders
12 * `U`, `V`, ... the corresponding spectral state (uppercase)
13 */
14import schnakenbergSource from '../../models/schnakenberg.m?raw';
15import brusselatorSource from '../../models/brusselator.m?raw';
16import allencahnSource from '../../models/allencahn.m?raw';
18export type Params = Record<string, number>;
20/** A tunable scalar the .m may take as an argument. */
21export interface ParamSpec {
22 key: string;
23 label: string;
24 value: number;
25 min: number;
26 max: number;
27 step: number;
30export interface MModel {
31 key: string;
32 label: string;
33 blurb: string;
34 /** Grid fields to render, one panel each. */
35 species: string[];
36 /** Spectral state names the .m advances. */
37 state: string[];
38 params: ParamSpec[];
39 /** Polynomial degree of the reaction in the fields, for grid dealiasing. */
40 pdeg: number;
41 /** Amplitude of the seeded perturbation handed to `init`. */
42 seedAmp: number;
43 /** MATLAB source — the algorithm itself. */
44 source: string;
47/** Spectral state names follow the grid-field names, uppercased. */
48const stateFor = (species: string[]): string[] => species.map((s) => s.toUpperCase());
50const schnakenberg: MModel = {
51 key: 'schnakenberg',
52 label: 'Schnakenberg',
53 blurb: 'Turing spots.',
54 species: ['u', 'v'],
55 state: stateFor(['u', 'v']),
56 params: [
57 { key: 'a', label: 'a', value: 0.1, min: 0.01, max: 0.5, step: 0.01 },
58 { key: 'b', label: 'b', value: 0.9, min: 0.1, max: 2, step: 0.05 },
59 { key: 'D1', label: 'D₁', value: 4e-4, min: 1e-5, max: 5e-3, step: 1e-5 },
60 { key: 'D2', label: 'D₂', value: 8e-3, min: 1e-4, max: 5e-2, step: 1e-4 },
61 { key: 'dt', label: 'dt', value: 0.05, min: 0.005, max: 0.5, step: 0.005 },
62 ],
63 pdeg: 3,
64 seedAmp: 1e-2,
65 source: schnakenbergSource,
66};
68const brusselator: MModel = {
69 key: 'brusselator',
70 label: 'Brusselator',
71 blurb: 'Turing stripes and spots.',
72 species: ['u', 'v'],
73 state: stateFor(['u', 'v']),
74 params: [
75 { key: 'A', label: 'A', value: 3, min: 0.5, max: 6, step: 0.1 },
76 { key: 'B', label: 'B', value: 9, min: 1, max: 15, step: 0.25 },
77 { key: 'D1', label: 'D₁', value: 3.33e-3, min: 1e-4, max: 2e-2, step: 1e-4 },
78 { key: 'D2', label: 'D₂', value: 1.67e-2, min: 1e-3, max: 1e-1, step: 1e-3 },
79 { key: 'dt', label: 'dt', value: 0.02, min: 0.002, max: 0.1, step: 0.002 },
80 ],
81 pdeg: 3,
82 seedAmp: 1e-2,
83 source: brusselatorSource,
84};
86const allencahn: MModel = {
87 key: 'allencahn',
88 label: 'Allen–Cahn',
89 blurb: 'One species: interfaces form, then coarsen.',
90 species: ['u'],
91 state: stateFor(['u']),
92 params: [
93 { key: 'eps2', label: 'ε²', value: 1e-3, min: 1e-4, max: 1e-2, step: 1e-4 },
94 { key: 'dt', label: 'dt', value: 0.02, min: 0.002, max: 0.2, step: 0.002 },
95 ],
96 pdeg: 3,
97 seedAmp: 1e-2,
98 source: allencahnSource,
99};
101export const mModels: MModel[] = [schnakenberg, brusselator, allencahn];
103export const mModelByKey = (key: string): MModel | undefined =>
104 mModels.find((m) => m.key === key);
106export const defaultParams = (m: MModel): Params =>
107 Object.fromEntries(m.params.map((p) => [p.key, p.value]));
109/** Named parameter presets shown in the UI dropdown. The pattern length scale
110 * goes as 1/sqrt(D), so scaling both diffusivities moves the spot size without
111 * changing the dynamics. */
112export interface Preset {
113 key: string;
114 label: string;
115 modelKey: string;
116 /** Overrides applied on top of the model's default parameters. */
117 params?: Params;
120export const presets: Preset[] = [
121 { key: 'schnak-spots', label: 'Schnakenberg — spots', modelKey: 'schnakenberg' },
122 {
123 key: 'schnak-coarse',
124 label: 'Schnakenberg — coarse spots',
125 modelKey: 'schnakenberg',
126 params: { D1: 1e-3, D2: 2e-2 },
127 },
128 {
129 key: 'schnak-fine',
130 label: 'Schnakenberg — fine spots',
131 modelKey: 'schnakenberg',
132 params: { D1: 1.6e-4, D2: 3.2e-3 },
133 },
134 { key: 'brussel', label: 'Brusselator — stripes & spots', modelKey: 'brusselator' },
135 { key: 'allencahn', label: 'Allen–Cahn — coarsening', modelKey: 'allencahn' },
136];
moveopenescclose