import { useEffect, useMemo, useState } from "react"; import { DEFAULT_INSTANCE, INSTANCES, getInstance, PROBLEM_ID, } from "../../problems/laplace2d/spec"; import { SOLVERS } from "../../solvers"; import type { ResultFile, ResultPoint } from "../../harness/resultSchema"; import { environmentLabel, fetchCommittedResults, isResultFile, } from "../results"; import { solverColorVar } from "../colors"; import { sweepInBrowser } from "../workerClient"; import { solverSource } from "../matlabSources"; 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(DEFAULT_INSTANCE); 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 [copied, setCopied] = useState(false); const inst = getInstance(instanceId); const visibleSolverList = SOLVERS.filter((s) => !hidden.has(s.id)); const cliCommand = `npx https://concept-collection.github.io/fastandaccurate/cli.tgz?v=${__BUILD_ID__} ` + `run --instance ${instanceId}` + (visibleSolverList.length === 1 ? ` --solver ${visibleSolverList[0].id}` : "") + ` --label "my machine"`; 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); } } 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}

Solvers

Each solver is a MATLAB function file implementing the interface in the specification; the same file runs in the browser via numbl and from the command line.

{SOLVERS.map((s) => (
{s.name}{" "} {s.id} v{s.version} · {s.backend} ·{" "} {s.runtime === "matlab" ? "runs in MATLAB via the command line" : "runs via numbl in the browser and command line"}

{s.description}

solver.m
              {solverSource(s.id)}
            
view on GitHub
))}

Work-precision results

{committedError && (

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

)}
{SOLVERS.map((s) => ( {" "} {s.runtime === "numbl" ? ( ) : ( MATLAB only (via the CLI) )} ))}
{runStatus &&

{runStatus}

}

Run this on your machine

This command runs the{" "} {visibleSolverList.length === 1 ? `${visibleSolverList[0].id} sweep` : "same sweeps"}{" "} on the {instanceId} instance (node 20 or newer) and writes result JSON files. Load them below to see them on this chart, or submit them by pull request (see About).

          {cliCommand}
        

Solution and error

Compute one solve at a chosen resolution and compare the field with the exact solution, on a shared color scale. The error map shows the absolute pointwise difference on a log scale; the errors reported in the results above are measured at the evaluation points, which can be shown on the error map.

); }