1/**
2 * The available .m models.
3 *
4 * Parameter metadata (names, defaults, slider ranges), species names and the
5 * dealiasing degree stay in src/solver/models.ts: the host owns those, and
6 * sharing them means the reference solver used by the tests and the .m running
7 * on the GPU are always configured identically. This module only attaches each
8 * model's MATLAB source.
9 *
10 * Naming convention, relied on by the app and 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 { models, type ModelSpec, type ParamSpec } from '../solver/models.ts';
15import schnakenbergSource from '../../models/schnakenberg.m?raw';
16import brusselatorSource from '../../models/brusselator.m?raw';
17import allencahnSource from '../../models/allencahn.m?raw';
19const sources: Record<string, string> = {
20 schnakenberg: schnakenbergSource,
21 brusselator: brusselatorSource,
22 allencahn: allencahnSource,
23};
25export interface MModel {
26 key: string;
27 label: string;
28 blurb: string;
29 /** Grid fields to render, one panel each. */
30 species: string[];
31 /** Spectral state names the .m advances. */
32 state: string[];
33 params: ParamSpec[];
34 /** Polynomial degree of the reaction, for grid dealiasing. */
35 pdeg: number;
36 /** Amplitude of the seeded perturbation. */
37 seedAmp: number;
38 /** MATLAB source — the algorithm itself. */
39 source: string;
40}
42const fromSpec = (m: ModelSpec): MModel => ({
43 key: m.key,
44 label: m.label,
45 blurb: m.blurb,
46 species: m.species,
47 state: m.species.map((s) => s.toUpperCase()),
48 params: m.params,
49 pdeg: m.pdeg,
50 seedAmp: m.seedAmp,
51 source: sources[m.key],
52});
54export const mModels: MModel[] = models
55 .filter((m) => sources[m.key] !== undefined)
56 .map(fromSpec);
58export const mModelByKey = (key: string): MModel | undefined =>
59 mModels.find((m) => m.key === key);