// Static figures for Chapters 1 to 4. import { Arrowheads, Figure, Label, Node, arrow } from './svg.tsx' import { ink, method } from '../plot/palette.ts' /** The mesh, the three-point stencil, and the band it puts in the matrix. */ export function ThreePointStencil() { const L = 70 const R = 470 const Y = 96 const N = 8 const xs = Array.from({ length: N + 1 }, (_, i) => L + (i * (R - L)) / N) const hit = [3, 4, 5] return (
{/* the mesh */} {xs.map((x, i) => ( ))} {/* h */} {/* the stencil, sitting on one interior node */} {hit.map((i, k) => ( ))} {/* the matrix band */} {Array.from({ length: 7 }, (_, r) => Array.from({ length: 7 }, (_, c) => { const d = Math.abs(r - c) if (d > 1) return null return ( ) }), )}
) } /** Where manufactured data comes from, and what is then compared with what. */ export function ManufacturedLoop() { const boxes = [ { x: 6, w: 126, t: 'pick u(x)', s: 'any function you like' }, { x: 148, w: 206, t: 'f := −u″, α := u(0), β := u(1)', s: 'differentiate by hand' }, { x: 370, w: 146, t: 'solve for uₕ', s: 'the method under test' }, { x: 532, w: 178, t: 'error = uₕ − u', s: 'known exactly, everywhere' }, ] const Y = 42 return (
{boxes.map((b, i) => ( {i < boxes.length - 1 ? ( ) : null} ))}
) } /** The V: discretisation down, roundoff up, and the best attainable error. */ export function RoundoffFloor() { const L = 66 const R = 546 const T = 24 const B = 168 // x is log10 N from 1 to 7; y is log10 error, 1 at the top and 1e-10 at the foot const sx = (v: number) => L + ((v - 1) / 6) * (R - L) const sy = (v: number) => T + (-v / 10) * (B - T) const disc = (n: number) => -2.3 - 2 * (n - 1) const round = (n: number) => -16 + 1.925 * n const total = (n: number) => Math.log10(10 ** disc(n) + 10 ** round(n)) const path = (f: (n: number) => number) => { const pts: string[] = [] for (let i = 0; i <= 240; i++) { const n = 1 + (6 * i) / 240 const y = f(n) if (y > 0 || y < -10) continue pts.push(`${sx(n).toFixed(1)} ${sy(y).toFixed(1)}`) } return 'M ' + pts.join(' L ') } const nStar = 4 // where the two contributions are equal return (
{[0, -2, -4, -6, -8, -10].map((e) => ( ))} {[1, 2, 3, 4, 5, 6, 7].map((n) => ( ))}
) } /** Numerov changes the right-hand side and leaves the matrix alone. */ export function CompactScheme() { const CX = [268, 336, 404] const cell = (x: number, y: number, v: string | null, colour: string) => v === null ? ( ) : ( <> ) const row = (y: number, name: string, vals: (string | null)[], colour: string, note: string) => ( {vals.map((v, i) => ( {cell(CX[i], y, v, colour)} ))} ) return (
{['i−1', 'i', 'i+1'].map((t, i) => ( ))} {row(52, 'both schemes', ['−1', '2', '−1'], method.fd2, '÷ h², tridiagonal')} {row(142, 'three-point', [null, 'fᵢ', null], ink.secondary, 'order 2')} {row(184, 'Numerov', ['f/12', '10f/12', 'f/12'], method.fd4, 'order 4, for one pass over an array')}
) } /** Equispaced against Chebyshev points, and where they come from. */ export function ChebyshevPoints() { const N = 16 const L = 172 const R = 562 const cx = (L + R) / 2 const rad = (R - L) / 2 const YARC = 216 const cheb = Array.from({ length: N + 1 }, (_, j) => 0.5 * (1 - Math.cos((Math.PI * j) / N))) const equi = Array.from({ length: N + 1 }, (_, j) => j / N) const X = (t: number) => L + t * (R - L) return (
{cheb.map((t, j) => { const th = Math.PI - (Math.PI * j) / N const ax = cx + rad * Math.cos(th) const ay = YARC - rad * Math.sin(th) return ( ) })} {cheb.map((t, j) => ( ))} {equi.map((t, j) => ( ))}
) }