import { useEffect, useMemo, useState } from "react"; import { INSTANCES, getInstance, PROBLEM_ID, } from "../../problems/laplace2d/spec"; import { SOLVERS, getSolver } from "../../solvers"; import { buildResultFile, type ResultFile, type ResultPoint, } from "../../harness/resultSchema"; import { environmentLabel, fetchCommittedResults, isResultFile, RESULTS_REPO_URL, } from "../results"; import { solverColorVar } from "../colors"; import { sweepInBrowser } from "../workerClient"; import { WorkPrecisionChart, type ChartCurve, } from "../components/WorkPrecisionChart"; import { PointsTable } from "../components/PointsTable"; import { DomainView } from "../components/DomainView"; import { SolutionSection } from "../components/SolutionSection"; const REPO_URL = "https://github.com/concept-collection/fastandaccurate"; const SPEC_URL = `${REPO_URL}/blob/main/docs/problems/laplace-dirichlet-2d.md`; interface LocalRun { key: string; solverId: string; instanceId: string; repeats: number; points: ResultPoint[]; done: boolean; } export function ProblemPage({ problemId }: { problemId: string }) { const [instanceId, setInstanceId] = useState(INSTANCES[1].id); const [committed, setCommitted] = useState(null); const [committedError, setCommittedError] = useState(null); const [loaded, setLoaded] = useState([]); const [localRuns, setLocalRuns] = useState([]); const [hidden, setHidden] = useState>(new Set()); const [running, setRunning] = useState(null); const [runStatus, setRunStatus] = useState(null); const [repeats, setRepeats] = useState(3); const [machineLabel, setMachineLabel] = useState(""); const inst = getInstance(instanceId); useEffect(() => { fetchCommittedResults() .then(setCommitted) .catch((err) => setCommittedError(err instanceof Error ? err.message : String(err)) ); }, []); const allSolverIds = useMemo(() => { const ids = new Set(SOLVERS.map((s) => s.id)); committed?.forEach((r) => ids.add(r.solver.id)); loaded.forEach((r) => ids.add(r.solver.id)); return [...ids]; }, [committed, loaded]); const curves: ChartCurve[] = useMemo(() => { const out: ChartCurve[] = []; const color = (id: string) => solverColorVar(id, allSolverIds); committed ?.filter((r) => r.problem === PROBLEM_ID && r.instance === instanceId) .forEach((r, i) => { out.push({ key: `committed:${i}`, solverId: r.solver.id, label: `${r.solver.id} — ${environmentLabel(r)}`, color: color(r.solver.id), points: r.points, }); }); loaded .filter((r) => r.problem === PROBLEM_ID && r.instance === instanceId) .forEach((r, i) => { out.push({ key: `loaded:${i}`, solverId: r.solver.id, label: `${r.solver.id} — ${environmentLabel(r)} (loaded)`, color: color(r.solver.id), dash: "8 4", points: r.points, }); }); localRuns .filter((r) => r.instanceId === instanceId) .forEach((r) => { out.push({ key: r.key, solverId: r.solverId, label: `${r.solverId} — this browser`, color: color(r.solverId), dash: "4 4", open: true, points: r.points, }); }); return out.filter((c) => !hidden.has(c.solverId)); }, [committed, loaded, localRuns, instanceId, hidden, allSolverIds]); async function runSolver(solverId: string) { const key = `local:${solverId}:${instanceId}:${Date.now()}`; setLocalRuns((rs) => [ ...rs.filter( (r) => !(r.solverId === solverId && r.instanceId === instanceId) ), { key, solverId, instanceId, repeats, points: [], done: false }, ]); setRunning(solverId); try { const points = await sweepInBrowser( instanceId, solverId, repeats, (point, index, total) => { setRunStatus( `${solverId} on ${instanceId}: point ${index + 1}/${total} (n = ${point.n}) — rel max error ${point.relMax.toExponential(2)}` ); setLocalRuns((rs) => rs.map((r) => r.key === key ? { ...r, points: [...r.points, point] } : r ) ); } ); setLocalRuns((rs) => rs.map((r) => (r.key === key ? { ...r, points, done: true } : r)) ); setRunStatus(null); } catch (err) { setRunStatus( `${solverId} failed: ${err instanceof Error ? err.message : String(err)}` ); } finally { setRunning(null); } } async function downloadRun(run: LocalRun) { const manifest = getSolver(run.solverId); const result = await buildResultFile({ instance: getInstance(run.instanceId), solver: { id: manifest.id, version: manifest.version, backend: manifest.backend, source: "builtin", }, environment: { kind: "browser", runtime: navigator.userAgent, numblVersion: __NUMBL_VERSION__, machineLabel: machineLabel || undefined, browserReproducible: true, }, repeats: run.repeats, points: run.points, }); const blob = new Blob([JSON.stringify(result, null, 2) + "\n"], { type: "application/json", }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = `${PROBLEM_ID}.${run.instanceId}.${run.solverId}.browser.json`; a.click(); URL.revokeObjectURL(a.href); } function loadFiles(files: FileList | null) { if (!files) return; for (const file of Array.from(files)) { file.text().then((text) => { try { const data: unknown = JSON.parse(text); if (isResultFile(data)) { setLoaded((ls) => [...ls, data]); } else { alert(`${file.name} is not a fastandaccurate result file`); } } catch { alert(`${file.name}: not valid JSON`); } }); } } if (problemId !== PROBLEM_ID) { return ( <>

← problems

Unknown problem

No problem named {problemId}.{" "} Back to the problem list.

); } return ( <>

← problems

{PROBLEM_ID}

Interior Dirichlet Laplace problem on a star-shaped 2D domain

Solve Δu = 0 on the domain with boundary r(θ) = 1 + a·cos(kθ), with Dirichlet data u = g on the boundary. The data comes from an exact harmonic function, a sum of three logarithmic point sources placed a distance d outside the boundary, so errors are measured against the true solution rather than a reference computation. The distance d sets the difficulty: the closer the sources, the shorter the distance the data continues harmonically past the boundary, and methods whose representations assume that continuation lose it. A solver receives the curve (with derivatives), the boundary data as a function of the boundary parameter, and the evaluation points, and returns solution values at those points. The precise statement, solver interface, and timing protocol are in the specification.

{inst.description}

a {inst.a} k {inst.k} d {inst.d}

Work-precision results

{committedError && (

Committed results could not be loaded ({committedError}); showing local runs only.

)}
{SOLVERS.map((s) => ( {" "} ))}
{runStatus &&

{runStatus}

}
{localRuns .filter((r) => r.done && r.instanceId === instanceId) .map((r) => ( ))}

Solution and error

Compute one solve at a chosen resolution and compare the field with the exact solution. The solution uses a diverging scale about zero; the error is the absolute pointwise difference on a log scale.

The same sweeps run outside the browser with the command line, and both browser and command-line results are submitted by pull request to the results repository; see{" "} About.

); }