1import { createElement, Fragment } from 'react'
2import type { Chapter } from '../../ui/types.ts'
3import driver from '../twodim/driver.m?raw'
4import script from './fastpoisson.m?raw'
5import text from './text.md?raw'
6import { Convergence, WorkPrecision, fmtErr, type SweepOut } from '../onedim/panels.tsx'
7import { EXACT2D_CONTROL } from '../shared.ts'
8import type { MethodKey } from '../../plot/palette.ts'
10const SLOTS: MethodKey[] = ['fd2', 'fast']
12export const ch06: Chapter = {
13 id: 'fast-poisson',
14 nav: 'The fast Poisson solver',
15 part: 'Two dimensions',
16 title: 'The fast Poisson solver',
17 blurb: 'The same discretisation, diagonalised by the sine transform: a million unknowns in half a second.',
18 text,
19 labs: [
20 {
21 id: 'compare',
22 title: 'Elimination against the sine transform',
23 caption:
24 'Both curves are the same discretisation, so where they overlap they lie exactly on top of each other; the sine transform is drawn dashed so that the dense solve shows through. The dense solve stops at N = 32 because that is where it stops being possible.',
25 driver,
26 script,
27 manual: true,
28 editorOpen: true,
29 controls: [
30 EXACT2D_CONTROL,
31 {
32 kind: 'slider',
33 key: 'nmax',
34 label: 'finest N for the fast solver',
35 values: [128, 256, 512, 1024, 2048],
36 min: 0,
37 max: 4,
38 format: (v) => String(v),
39 },
40 ],
41 defaults: {
42 kind: 'expsin',
43 par: 1,
44 mode: 'sweep',
45 ns: [],
46 nmax: 512,
47 nmaxs: [32, 512],
48 timed: 1,
49 },
50 derive: (p) => ({
51 ...p,
52 ns: [8, 16, 32, 64, 128, 256, 512, 1024, 2048].filter((n) => n <= Number(p.nmax)),
53 nmaxs: [32, Number(p.nmax)],
54 }),
55 render: (d: SweepOut) =>
56 createElement(
57 Fragment,
58 null,
59 createElement(Convergence, {
60 key: 'c',
61 data: d,
62 style: { slots: SLOTS, dashes: [undefined, '7 5'], refs: [{ p: -2, label: 'slope −2' }] },
63 }),
64 createElement(WorkPrecision, { key: 'w', data: d, style: { slots: SLOTS, dashes: [undefined, '7 5'] } }),
65 ),
66 summary: (d: SweepOut) => {
67 const last = d.E[1].length - 1
68 return [
69 { label: 'finest error', value: fmtErr(d.E[1][last]) },
70 { label: 'in', value: `${(d.T[1][last] ?? 0).toFixed(0)} ms` },
71 ]
72 },
73 },
74 ],
75}