1# mesh-pde-solver
3Upload a quadrilateral surface mesh, pick a PDE, tweak its right-hand side
4and coefficients, and solve it **on the surface** — entirely in your browser.
5The mesh is converted to Gmsh format with [meshio](https://github.com/nschloe/meshio)
6(via [Pyodide](https://pyodide.org)), and the PDE is solved by
7[surfacefun](https://github.com/danfortunato/surfacefun) running on
8[numbl](https://numbl.org), a MATLAB-compatible runtime, in a web worker.
9The solution renders in a rotatable 3D view (drag to rotate, scroll to zoom).
11## PDEs
13- **Poisson (Laplace–Beltrami)** — Δu = f. On a closed surface the problem is
14 rank-deficient: f is projected to mean zero and the mean-zero solution is
15 returned. On an open surface, zero Dirichlet data is imposed.
16- **Helmholtz (variable coefficient)** — (Δ + c)u = f with c(x, y, z) an
17 arbitrary expression.
19The right-hand side f and coefficient c are MATLAB expressions in the surface
20coordinates x, y, z (elementwise operators: `.*`, `.^`, …), with presets to
21start from. The polynomial order per patch is adjustable (accuracy vs. time).
23## Meshes
25Uploads go through meshio, so any of `.msh .vtk .vtu .obj .off .ply .inp
26.mesh .bdf .avs` works — but the mesh **must contain quadrilateral cells**
27(surfacefun computes on quad patches; triangle-only meshes are rejected).
28Two sample meshes are bundled. The converted Gmsh file can be downloaded.
29Whether the surface is closed or open is detected from the edge connectivity.
31## How it works
331. `src/mesh/` — meshio in Pyodide parses the upload, keeps the quad cells,
34 and writes a canonical Gmsh MSH 2.2 ASCII file plus preview arrays.
352. `src/engine/` — each solve boots a fresh managed numbl session
36 (`createNumblSession` from `numbl/browser`): numbl owns the worker and
37 VFS and bootstraps the [mip](https://github.com/mip-org) package manager.
38 The host stages `mesh.msh` and `params.json` and runs
39 [`matlab/main.m`](matlab/main.m) standalone — it begins with
40 `mip load --install surfacefun`, solves, and writes `result.json`, which
41 the host reads back before disposing the worker.
423. `matlab/solve_pde.m` — parses the mesh (`load_gmsh_quads.m`), builds a
43 `surfacemesh` from the quads, `resample`s it to the requested order, and
44 solves with `surfaceop`.
454. `src/render/SurfaceView.tsx` — three.js view of the quad mesh or the
46 per-patch solution grids with a parula colormap.
48The first visit downloads the Python runtime (~15 MB, browser-cached) and
49the surfacefun/chebfun packages (~28 MB). Installed MATLAB packages persist
50in IndexedDB across page loads (numbl wipes them after 24 h of inactivity),
51so later visits skip the package downloads.
53## Development
55```bash
56npm install
57npm run dev # local dev server
58npm run build # static build in dist/
59npm run engine-test # headless solver check in Node (no browser)
60python3 scripts/make_samples.py # regenerate public/samples/
61```
63The engine test runs the exact MATLAB project the worker runs, shimming
64numbl's synchronous-XHR `websave`/`webread` with curl (responses cached in
65`.cache/`), and checks a Poisson solve against an exact spherical-harmonic
66solution.
68Requires numbl >= 0.4.10 (the `numbl/browser` managed-session entry with
69`readFile`).