1/**
2 * Shared .m files every model compiles against: the operator library and the
3 * solvers. A model calls these by name (`richardson(...)`, `dlap(...)`) the
4 * way it calls `synth` — except these are ordinary MATLAB, compiled through
5 * the same pipeline and expanded into the caller at compile time
6 * (src/mgpu/inlineCalls.ts), so a call costs exactly what writing the body
7 * inline would.
8 *
9 * MATLAB file-visibility rules apply: only a file's namesake function is
10 * callable from other files, and a function defined in the model shadows a
11 * lib of the same name.
12 */
13import dlapSource from '../../lib/dlap.m?raw';
14import richardsonSource from '../../solvers/richardson.m?raw';
15import bicgstabSource from '../../solvers/bicgstab.m?raw';
16import gmresSource from '../../solvers/gmres.m?raw';
18export interface LibFile {
19 name: string;
20 source: string;
21}
23/** The operator: dlap = lap_g - lap_s applied to a spectral field. */
24export const operatorLibs: LibFile[] = [{ name: 'dlap.m', source: dlapSource }];
26/** The solvers for (I - dtD*lap_g) X = B. All share dlap's operator. */
27export const solverLibs: LibFile[] = [
28 { name: 'richardson.m', source: richardsonSource },
29 { name: 'bicgstab.m', source: bicgstabSource },
30 { name: 'gmres.m', source: gmresSource },
31];
33/** Everything a model may call. */
34export const modelLibs: LibFile[] = [...operatorLibs, ...solverLibs];
36/** Where each shared file lives on disk, for display. */
37export const libPath = (name: string): string =>
38 operatorLibs.some((f) => f.name === name) ? `lib/${name}` : `solvers/${name}`;
40export type SolverKey = 'richardson' | 'bicgstab' | 'gmres';
41export const solverKeys: SolverKey[] = ['richardson', 'bicgstab', 'gmres'];
42export const DEFAULT_SOLVER: SolverKey = 'richardson';
44/** What each solver actually takes: richardson needs no inner products, so
45 * no weights; only gmres sizes a basis bank, so only it takes nlm. */
46const SOLVE_FORWARD: Record<SolverKey, string> = {
47 richardson: 'richardson(B, dtD, lam, filt, Vtx, Vty, Vtz, Vpx, Vpy, Vpz, niter)',
48 bicgstab: 'bicgstab(B, dtD, lam, filt, wlm, Vtx, Vty, Vtz, Vpx, Vpy, Vpz, niter)',
49 gmres: 'gmres(B, dtD, lam, filt, wlm, Vtx, Vty, Vtz, Vpx, Vpy, Vpz, nlm, niter)',
50};
52/**
53 * The one-line shim behind the models' `solve(...)` call. The models pass
54 * every argument any solver could want, and this host-generated file
55 * forwards to the chosen one — so which solver runs is a compile-time choice
56 * the app's solver control makes (swapping recompiles, like changing niter),
57 * while the models stay identical across solvers. A model may also bypass
58 * the shim and call a solver by name.
59 */
60export function solveShim(solver: SolverKey): LibFile {
61 return {
62 name: 'solve.m',
63 source:
64 `% Host-generated: forwards the models' solve(...) call to the solver\n` +
65 `% selected in the app. See solvers/${solver}.m.\n` +
66 `function X = solve(B, dtD, lam, filt, wlm, Vtx, Vty, Vtz, Vpx, Vpy, Vpz, nlm, niter)\n` +
67 ` X = ${SOLVE_FORWARD[solver]};\n` +
68 `end\n`,
69 };
70}