import { createElement } from 'react' import type { Chapter } from '../../ui/types.ts' import driver from '../onedim/driver.m?raw' import fd2 from '../ch01/fd2.m?raw' import richardson from './richardson.m?raw' import text from './text.md?raw' import { Convergence, fmtErr, type SweepOut } from '../onedim/panels.tsx' import { KIND_CONTROL, NS_1D } from '../shared.ts' export const ch02: Chapter = { id: 'limits', nav: 'Second order to its limit', part: 'One dimension', title: 'Second order, to its limit', blurb: 'Conditioning, the roundoff floor at about eight digits, and Richardson extrapolation.', text, labs: [ { id: 'floor', title: 'Refining until it stops helping', caption: 'Nine resolutions from 16 to 262144 intervals. The last few take a second or two each; the whole sweep runs on request.', driver, script: fd2, manual: true, controls: [ KIND_CONTROL, { kind: 'slider', key: 'nmax', label: 'finest N', values: [16384, 65536, 262144, 1048576], min: 0, max: 3, format: (v) => String(v), }, ], defaults: { kind: 'smooth', mode: 'sweep', ns: [], nmax: 262144, nmaxs: [1e9], timed: 1 }, derive: (p) => ({ ...p, ns: [16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576].filter((n) => n <= Number(p.nmax)), }), render: (d: SweepOut) => createElement(Convergence, { data: d, style: { slots: ['fd2'], refs: [ { p: -2, label: 'slope −2: discretisation' }, { p: 2, label: 'slope +2: roundoff × κ(A)', at: [1e3, 2e-13] }, ], }, height: 340, }), summary: (d: SweepOut) => { const es = d.E[0] let bi = 0 es.forEach((v, i) => { if (v != null && (es[bi] == null || v < (es[bi] as number))) bi = i }) return [ { label: 'best error', value: fmtErr(es[bi]) }, { label: 'at N', value: String(d.ns[bi]) }, ] }, }, { id: 'richardson', title: 'Two second-order solves, one fourth-order answer', caption: 'Change the manufactured solution to lowreg and watch the gain evaporate.', driver, script: richardson, editorOpen: true, controls: [KIND_CONTROL], defaults: { kind: 'smooth', mode: 'sweep', ns: NS_1D, nmaxs: [1e9, 1e9], timed: 0 }, render: (d: SweepOut) => createElement(Convergence, { data: d, style: { slots: ['fd2', 'fd4'], refs: [ { p: -2, label: 'slope −2' }, { p: -4, label: 'slope −4' }, ], }, }), summary: (d: SweepOut) => { const q = d.orders[1]?.[d.orders[1].length - 1] return [ { label: 'extrapolated error', value: fmtErr(d.E[1]?.[d.E[1].length - 1]) }, { label: 'observed order', value: q == null ? '--' : q.toFixed(2) }, ] }, }, ], }