// Figures for the two-dimensional labs: the computed field, and the pointwise // error beside it on a logarithmic colour scale, which is the only way to see // both the interior and the corners of an error that spans decades. import Field from '../../plot/Field.tsx' import type { Num } from '../../engine/types.ts' import { fmtErr } from '../onedim/panels.tsx' export interface Single2DOut { names: string[] ms: number maxerr: Num unknowns: number x: number[] y: number[] U: Num[][] Err: Num[][] } /** A signed field gets the diverging ramp; a one-signed field the sequential * one, so that the whole colour range is used either way. */ function signOf(z: Num[][]): 'div' | 'seq' { let lo = Infinity let hi = -Infinity for (const row of z) { for (const v of row) { if (v == null || !isFinite(v)) continue if (v < lo) lo = v if (v > hi) hi = v } } return lo < 0 && hi > 0 ? 'div' : 'seq' } /** Decades to span in an error picture: what the data actually covers. */ function decadesOf(z: Num[][]): number { let lo = Infinity let hi = 0 for (const row of z) { for (const v of row) { if (v == null || !isFinite(v) || v <= 0) continue if (v < lo) lo = v if (v > hi) hi = v } } if (!isFinite(lo) || hi <= 0) return 6 return Math.min(14, Math.max(3, Math.ceil(Math.log10(hi / lo)))) } export function Fields2D({ data, xDomain = [0, 1], yDomain = [0, 1], curves, }: { data: Single2DOut xDomain?: [number, number] yDomain?: [number, number] curves?: { x: number[]; y: number[]; color?: string }[] }) { const emax = data.maxerr == null || !isFinite(data.maxerr) ? 1 : Math.log10(data.maxerr) return (
) }