6292f12A benchmark chapter, and offline benchmarks to compare it againstJeremy Magland 1import { createElement } from 'react'
2import type { Chapter, Control } from '../../ui/types.ts'
3import driver from './driver.m?raw'
4import script from './pacman.m?raw'
5import text from './text.md?raw'
6import { Fields2D, type Single2DOut } from '../twodim/panels.tsx'
7import { fmtErr } from '../onedim/panels.tsx'
8import { BenchSweep, type BenchOut } from './panels.tsx'
9import type { Num } from '../../engine/types.ts'
11interface FieldOut extends Single2DOut {
12 cx: number[]
13 cy: number[]
14}
16const KIND: Control = {
17 kind: 'select',
18 key: 'kind',
19 label: 'ground truth',
20 options: [
21 { value: 'both', label: 'singular + smooth (generic)' },
22 { value: 'sing', label: 'singular only: r^(2/3) sin(2θ/3)' },
23 { value: 'smooth', label: 'smooth only: log|z − z₀|' },
24 ],
25}
27/** Each method's resolution ladder behind the shared coarse-to-finest slider. */
28const LEVELS: number[][] = [
29 [32, 64, 96, 128], // grid intervals per unit
30 [8, 16, 32, 48], // basis degree
31 [4, 6, 8, 10], // refinement depth
32 [10, 20, 30, 40], // Chebyshev points per direction
33]
35const NSM = [
36 [8, 16, 32, 64, 128],
37 [4, 8, 16, 32, 48],
38 [2, 4, 6, 8, 10],
39 [6, 10, 16, 26, 40],
40]
42function bestOf(d: BenchOut): { v: number; name: string } {
43 let v = Infinity
44 let name = ''
45 d.E.forEach((row, k) => {
46 for (const e of row) {
47 if (e != null && isFinite(e) && e > 0 && e < v) {
48 v = e
49 name = d.names[k]
50 }
51 }
52 })
53 return { v, name }
54}
56export const ch11: Chapter = {
57 id: 'benchmarks',
58 nav: 'One problem, every method',
59 part: 'Beyond the square',
60 title: 'Benchmarks: one problem, every method',
61 blurb:
62 'A curved boundary with three corners, the four families of methods side by side, and timings you can extend beyond the browser.',
63 text,
64 labs: [
65 {
66 id: 'field',
67 title: 'The solution, and where each method hurts',
68 caption:
69 'The error picture is the method’s signature: the difference scheme concentrates its error at the corner, the double layer at the boundary (that ring is the close-evaluation problem of Chapter 10), and the collocation methods spread theirs.',
70 driver,
71 script,
72 manual: true,
73 controls: [
74 KIND,
75 {
76 kind: 'select',
77 key: 'mid',
78 label: 'method',
79 options: [
80 { value: 1, label: 'Shortley-Weller + SOR' },
81 { value: 2, label: 'harmonic basis' },
82 { value: 3, label: 'double layer, graded panels' },
83 { value: 4, label: 'Chebyshev, polar rectangle' },
84 ],
85 },
86 {
87 kind: 'slider',
88 key: 'level',
89 label: 'resolution',
90 values: [1, 2, 3, 4],
91 min: 1,
92 max: 4,
93 format: (v) => ['coarse', 'medium', 'fine', 'finest'][v - 1],
94 },
95 ],
96 defaults: { kind: 'both', mode: 'field', mid: 1, level: 2 },
97 derive: (p) => ({ ...p, n: LEVELS[Number(p.mid) - 1][Number(p.level) - 1] }),
98 render: (d: FieldOut) =>
99 createElement(Fields2D, {
100 data: d,
101 xDomain: [-1.0625, 1.0625],
102 yDomain: [-1.0625, 1.0625],
103 curves: [{ x: d.cx, y: d.cy }],
104 }),
105 summary: (d: FieldOut) => [
106 { label: 'unknowns', value: String(d.unknowns) },
107 { label: 'max error', value: fmtErr(d.maxerr) },
108 ],
109 },
110 {
111 id: 'bench',
112 title: 'The benchmark',
113 caption:
114 'The first plot is only meaningful curve by curve, because each method refines its own parameter; the second, against wall clock, is the comparison. Results from the offline scripts land in the second plot as dashed curves.',
115 driver,
116 script,
117 manual: true,
118 editorOpen: true,
119 controls: [KIND],
120 defaults: { kind: 'both', mode: 'sweep', nsm: NSM },
121 render: (d: BenchOut, p) => createElement(BenchSweep, { data: d, kind: String(p.kind) }),
122 summary: (d: BenchOut) => {
123 const b = bestOf(d)
124 const t = d.T.flat().reduce((s: number, v: Num) => s + (v ?? 0), 0)
125 return [
126 { label: 'best error', value: `${fmtErr(b.v)} (${b.name})` },
127 { label: 'time in solves', value: t < 1000 ? `${t.toFixed(0)} ms` : `${(t / 1000).toFixed(1)} s` },
128 ]
129 },
130 },
131 ],
132}