// Figures for the introduction: what the problem is, on what domains, and // what the spread in accuracy-against-cost looks like before any of it is // measured. import type { ReactNode } from 'react' import { Arrowheads, Figure, Label, Node, arrow } from './svg.tsx' import { ink, method, seqColor } from '../plot/palette.ts' /** A closed wobbly curve, so that "a region" does not read as "a disc". */ function blob(cx: number, cy: number, rx: number, ry: number, phase: number): string { const pts: string[] = [] for (let i = 0; i < 72; i++) { const t = (2 * Math.PI * i) / 72 const r = 1 + 0.1 * Math.cos(3 * t + phase) + 0.045 * Math.sin(5 * t + 1.3) pts.push(`${(cx + rx * r * Math.cos(t)).toFixed(1)} ${(cy + ry * r * Math.sin(t)).toFixed(1)}`) } return `M ${pts.join(' L ')} Z` } /** Outward normal of the blob at parameter t, for the Neumann panel. */ function blobPoint(cx: number, cy: number, rx: number, ry: number, phase: number, t: number) { const r = 1 + 0.1 * Math.cos(3 * t + phase) + 0.045 * Math.sin(5 * t + 1.3) const dr = -0.3 * Math.sin(3 * t + phase) + 0.225 * Math.cos(5 * t + 1.3) const x = cx + rx * r * Math.cos(t) const y = cy + ry * r * Math.sin(t) const dx = rx * (dr * Math.cos(t) - r * Math.sin(t)) const dy = ry * (dr * Math.sin(t) + r * Math.cos(t)) const n = Math.hypot(dx, dy) return { x, y, nx: dy / n, ny: -dx / n } } const PANEL_W = 232 const CY = 108 function Panel({ x, heading, interior, sub, muted, children, }: { x: number heading: string interior: string sub: string muted?: boolean children?: ReactNode }) { return ( {children} ) } /** Laplace against Poisson, Dirichlet against Neumann, in one row. */ export function DirichletProblem() { const cx = PANEL_W / 2 const rx = 74 const ry = 54 const normals = [0.4, 1.5, 2.6, 3.7, 4.8, 5.9].map((t) => blobPoint(cx, CY, rx, ry, 0.7, t)) return (
{normals.map((p, i) => ( ))}
) } /** The four domains, in the order the tutorial meets them. */ export function Domains() { const c = ink.node const box = (i: number) => 12 + i * 176 return (
{/* 1-D interval */} {Array.from({ length: 9 }, (_, i) => ( ))} {/* unit square */} {Array.from({ length: 5 }, (_, i) => ( ))} {/* L-shape */} {/* smooth curve */} {Array.from({ length: 18 }, (_, i) => { const p = blobPoint(76, 92, 56, 54, 2.1, (2 * Math.PI * i) / 18) return })}
) } /** Schematic of the spread the tutorial measures. Not data. */ export function AccuracyCost() { const L = 66 const R = 470 const T = 26 const B = 176 // log10 time from -1 to 3.5 ms across; log10 error from 0 at the top to -16 const sx = (v: number) => L + ((v + 1) / 4.5) * (R - L) const sy = (v: number) => T + (-v / 16) * (B - T) const curve = (pts: [number, number][]) => 'M ' + pts.map(([t, e]) => `${sx(t).toFixed(1)} ${sy(e).toFixed(1)}`).join(' L ') const series: { key: keyof typeof method; label: string; pts: [number, number][] }[] = [ { key: 'fd2', label: 'second order', pts: [[-0.9, -1.0], [0.0, -2.6], [1.2, -4.4], [2.4, -6.0], [3.4, -7.3]] }, { key: 'fd4', label: 'sixth order', pts: [[-0.5, -1.4], [0.1, -5.0], [0.7, -9.0], [1.3, -13.0], [2.6, -13.4]] }, { key: 'spectral', label: 'spectral', pts: [[-0.2, -2.0], [0.15, -6.5], [0.5, -11.5], [0.9, -14.0], [2.0, -14.0]] }, { key: 'bie', label: 'boundary integral', pts: [[0.0, -3.0], [0.35, -9.0], [0.8, -15.4], [1.9, -15.6]] }, ] return (
{[0, -4, -8, -12, -16].map((e) => ( ))} {series.map((s, i) => { const last = s.pts[s.pts.length - 1] const ly = T + 16 + i * 22 return ( ) })}
) }