All documentation

#Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project follows Semantic Versioning.

Note: Pre-0.1.0 history (releases 0.0.1 through 0.0.7) lives at sachncs/bounded-commuting-discrete-trace-preserving-projections. The current canonical repository is sachncs/traceprojector.

#[Unreleased]

#Added

  • examples/: ten runnable programs (quick start, your own mesh, the four form degrees, a singular field, commuting, boundary values, refinement, time-dependent data, worker threads, higher order), each with its recorded output; validation/examples.test.js runs them. validateMeshInput is exported, to check a mesh without building anything, and parseGmsh reads an ASCII Gmsh .msh file (formats 2.2 and 4.1, first-order tetrahedra) into the two arrays the operators take, refusing anything else with a ValidateError.

  • The playground compares operators: a Web Worker runs Projector, CanonicalProjector, BoundedCommutingProjector, StableProjector and TracePreservingProjector on smooth, singular, discontinuous and localized fields, on a cube, a pasted JSON mesh or an uploaded Gmsh .msh, shows what each one cannot answer, measures the commuting and boundary-value residuals with their cost, refines near the centre, and exports a program that reproduces the run (scripts/verify-lab-code.mjs runs every exported program).

  • ZeroTraceProjector, BoundedCommutingProjector and StableProjector have count(l) and edge(index), so a caller can loop over every coefficient without reaching into the weights.

  • validation/showcase.test.js: every public export must have an API reference entry and a recipe or a stated reason it needs none.

  • TracePreservingProjector({degree: p}) for p >= 1: the boundary operator above the lowest order (boundary-traces.js, high-order-boundary.js, high-order-trace-preserving.js), evaluated with local(u, du, l). Validated at p = 1 (all four degrees) and p = 2 (l = 0) on cubes: trace preserved to 10⁻¹³, projection to 5·10⁻¹³, commuting to 10⁻¹¹ for fields with a discrete trace. Its stability is not measured.

  • CoefficientPool (traceprojector/parallel): coefficients of the bounded operators on any number of worker threads, bitwise identical to serial.

  • npm run bench, bench:check, bench:update: solver and weight-pipeline benchmarks in calibration units, with a committed baseline.

  • Solver certificates (residual, stationarity, duality gap, factor size) with limits fixed in validation/tolerances.json.

  • Documentation on the website, standalone: a getting-started guide, a guide to choosing an operator, performance, a developer guide, and every other page of docs/, rendered from the repository's Markdown at https://sachncs.github.io/traceprojector/docs/ (no links out to GitHub). The code examples in the user guides are executed by validation/docs-examples.test.js.

  • HighOrderWeights.extensionConstant and validation/assumption-2-4.test.js: Assumption 2.4 of Arnold and Guzmán (the uniform bound on the right inverse of d on extended stars) is now measured, not only assumed: 0.002 to 0.36 across jitter, 100:1 stretch and p = 1, growing by 3% from n = 4 to n = 8.

  • HigherOrderProjector accepts boundaryConditions: true for the zero-trace version (weights vanish on the boundary entities); validated at p = 1 near the boundary for all four form degrees.

  • Paper claims W4 (partition of unity), W6 (norms of the boundary weights and their extensions) and W7 (discrete Poincaré constants) tested at lowest order; end-to-end commuting of the higher-order projection for degrees 0 to 3, and its stability for all four degrees (ratios 0.995 to 1.007).

  • banded-linear-algebra.js: reverse Cuthill–McKee ordering, skyline Cholesky and a minimum-norm solver by the method of multipliers.

  • ZeroTraceProjector and StableProjector (lowest order): locally L²-bounded projections built from the local weight functions of arXiv:2502.03601. Interior coefficients are integrals against the weights, so an input unbounded at an interior mesh vertex is projected stably. The boundary part still uses canonical degrees of freedom; see docs/VALIDATION.md for what is and is not established.

  • BoundedCommutingProjector (lowest order): the projection of arXiv:2502.03601 Thm 5.1 without boundary condition. Locally L²-bounded and commuting for every input, boundary included; does not preserve traces.

  • HigherOrderProjector: the locally bounded commuting projection of Arnold and Guzmán for any degree p and every form degree, with HighOrderWeights (weights of any degree), AgSpace (their degrees of freedom) and the correction Q_r. Commutes with d to 2.5e-13 and keeps its L² constant (1.007) on narrow bumps at p = 1.

  • refineTetrahedra and Projector.refine (conforming longest-edge bisection), Projector.sampler (point location cached across time steps) and projectInParallel (Node worker threads).

  • CanonicalProjector: canonical interpolation onto P_r^- Λ^k of any degree for all form degrees (Lagrange, Nédélec, Raviart–Thomas, DG), with the polynomial form spaces and the reference-element degrees of freedom it is built from. Commutes with d and preserves the trace.

  • TracePreservingProjector (lowest order): the full operator Π = mΠ(I − Π_∂) + Π_∂ of the boundary-preserving paper: a projection onto the Whitney forms that preserves the discrete trace and commutes with the exterior derivative for fields with a lowest-order trace (4e-14 measured). Built from the boundary weights, the Worsey–Farin extension and ZeroTraceProjector.

  • docs/VALIDATION.md and a validation/ suite with tolerances fixed before the first run (validation/tolerances.json).

  • npm run verify: lint, tests, build, export parity, types parity (tsd and a JS-versus-declaration check), publint, attw, and a consumer test that installs the packed tarball into an empty directory.

#Changed

  • docs/api.md is generated by scripts/gen-api.mjs from the declaration files (npm run docs, checked by npm run docs:check). It lacked StableProjector, ZeroTraceProjector, BoundedCommutingProjector, CanonicalProjector, HigherOrderProjector, TracePreservingProjector and CoefficientPool, and listed internal constants; it now lists exactly the public API. jsdoc-to-markdown is no longer a dependency.

  • The local minimum-norm solves use preconditioned conjugate gradients on the dual problem with sparse Cholesky and a minimum-degree ordering; one higher-order weight at p = 1 is 3 to 7 times faster than before (cell: 5.7 s to 0.78 s).

  • Dense typed-array polynomials, tabulated bubble bases and geometry-keyed caches in the higher-order weights.

  • The local problems of the higher-order weights are solved with a banded Cholesky factorization instead of a dense one. One minimum-norm solve of about 1,500 unknowns went from 1.9 s to 0.02 s; a whole weight of an interior entity at p = 1 on a 6 × 6 × 6 cube went from 3.1 s to 0.45 s (l = 1), 14.2 s to 2.0 s (l = 2) and 42.8 s to 5.7 s (l = 3). A zero-trace weight next to the boundary that exceeded an hour now takes seconds. Polynomial.evaluate uses precomputed powers.

  • README rewritten; docs/setup.md, development.md, testing.md and publishing.md merged into the developer guide; architecture.md, math.md, exceptions.md and CONTRIBUTING.md brought up to date.

  • Code style follows the Google JavaScript Style Guide (ESLint with eslint-config-google) instead of StandardJS. The reformat is mechanical: the unit tests and the bit-exact determinism output are unchanged.

  • The package is ESM-only (sideEffects: false). The CommonJS bundle was never reachable through the exports map and is no longer built; on Node 22.12 and later require('traceprojector') loads the ESM entry.

  • The README and package description no longer claim that Projector is bounded: it uses canonical degrees of freedom, and the paper's boundary weights only cross-check them.

  • CI runs on Node 24 and 26, audits production dependencies, and builds the site; the web:build script reference is now site:build.

#Fixed

  • The playground's exported program imported generateUnitCubeMesh from traceprojector, where it is not exported, and passed a placeholder cell index; it now runs as written. Two accessibility issues in the site footer (a skipped heading level and an aria-label that did not contain its visible text) are fixed.

  • The operators that take vertices and tetrahedra (ZeroTraceProjector, BoundedCommutingProjector, StableProjector, CanonicalProjector, HigherOrderProjector, TracePreservingProjector) accepted NaN or infinite coordinates, repeated vertices and flat tetrahedra silently, and raised a bare TypeError for a vertex that does not exist. They now check the mesh on construction and raise ValidateError, as Mesh does and as the getting-started guide says. Behaviour change: a mesh that used to be accepted by accident and is broken in one of these ways now fails at construction. Orientation is not checked by these operators, because they sort the vertices of each cell and give the same answer, to roundoff, for either orientation (validation/orientation.test.js), so meshes from Gmsh or TetGen with mixed orientation keep working. Mesh and Projector, which use the sign, still require positive orientation.

  • minimumNormSolveDense returned a non-minimal solution (up to 80% more energy) when the constraint matrix had a null space; it now always solves the dual system. Regression test added.

  • The deployed website loaded its assets from the host root and showed an unstyled page on GitHub Pages; it is now built with the /traceprojector base path.

  • The README's quick-start example printed a wrong value (it claimed about 1.365; the interpolant is 0.6937) and imported generateUnitCubeMesh from a path that does not export it.

  • Projections returned Infinity or NaN silently when the input field was not finite at a degree of freedom; they now throw ProjectError.

  • Geometry depended on the unit system. Meshes with edges below about 0.1 mm (in metres) were rejected as degenerate, point location failed on them, face normals were silently replaced by [0, 0, 1], and small 3x3 systems were declared singular. Degeneracy is now judged by the volume relative to the longest edge cubed (MIN_RELATIVE_VOLUME, 1e-10), and a degenerate surface triangle raises an error instead of inventing a normal.

#[0.1.0] — 2026-09-03

The first release under the traceprojector name on Node 26. Adds the new web/ playground, drops Babel, and finishes the file-layout rebrand.

#Added

  • New web/ workspace. A Next.js 16 + shadcn/ui playground that consumes the lib via npm workspaces, with a 3D tetrahedral-mesh viewer (three.js / @react-three/fiber), an API playground with copy-to-clipboard code export, and a live convergence plot (Recharts). Start it with npm run web:dev; build it with npm run web:build. A new web job in .github/workflows/ci.yml builds the playground on every push.
  • New "Try it online" entry in the root README.md that points at the bundled web playground, alongside a convexfolio-style What is this? / Who is this for? / What can it do? / Before you start / Installation / Your first run / Configuration / Where to go next skeleton. The original technical depth (API, math, architecture, performance, tech stack) is kept as a second half.
  • Projector.verifyBoundaryWeights (Section 6.3 cross-check): the exact boundary DoFs stay u(v), ∫_e u·t, ∫_f u·n for any input, and each wired §6.3 weight functional is applied to its boundary simplex's canonical discrete trace basis field (P¹ hat λ_v, Whitney 1-form W_e, face RT_0) to confirm it recovers the normalized DoF — see traceprojector/boundaryVerify.js and tests/weight.test.js.
  • Weight vertex-weight assembly fix after an Alfeld/Worsey-Farin split: the mesh appends barycenter vertices, so bweight.vertexWeight now receives a compact, remapped local vertex set for each boundary star. The previous full-vertex pass produced a singular stiffness matrix after the split and silently skipped every vertex weight.
  • Edge boundary weight ζ_{0,e}^1 (Section 6.3.2) on the lowest-order surface N_0 (Whitney 1-form) space: build the star's edge indexing, assemble the Whitney mass matrix, solve for η_e^1 = M^{-1}d from the intrinsic edge moments d_k = ∫_e W_k·t_e, and expose the duality functional (ζ, u) = (η_e^1, u) reproducing the edge degree of freedom for H(curl) traces in N_0 (eq. 6.31).
  • Face boundary weight ζ_{0,f}^2 (Section 6.3.3) on the lowest-order surface RT_0 (Raviart-Thomas) space: assemble the RT_0 mass matrix over the extended star, solve for η_f^2 = M^{-1}d from the featured-face normal moments d_k = ∫_f RT_k·n, and expose the duality functional (ζ, u) = (η_f^2, u) reproducing the face degree of freedom for H(div) traces in RT_0 (eq. 6.36).
  • Section 2.3 surface differential operators (grad_Γ, curl_Γ, div_Γ, rot_Γ) and the Section 6.3 barycenter tent μ on Alfeld-split faces, in the new traceprojector/surface.js module.
  • Section 6.3 boundary-weight cascade wired into Weight.compute(): vertexBoundaryWeights, edgeBoundaryWeights, and faceBoundaryWeights (built from bweight.vertexWeight / edgeWeight / faceWeight over each boundary vertex's star, edge's star, and face's extended star), stored on Projector via computeBoundaryWeights.
  • README sections: Tech stack, Security, Code of Conduct, centered header with aligned badges, and license copyright.
  • engines.node: ">=26.0.0" in package.json and a workspaces: ["web"] field. New convenience scripts web:dev, web:build, and web:start proxy into the workspace.
  • .gitignore entries for the web workspace: .next/, out/, next-env.d.ts, .turbo/.

#Changed

  • README is rewritten in the convexfolio skeleton (with the technical depth kept as a second half) and the GitHub URL is updated to sachncs/traceprojector in every badge.
  • CONTRIBUTING and SECURITY are updated to use the public class name Projector and the package name traceprojector (no more TraceProjector or Bcdtpp).
  • Docs (docs/architecture.md, docs/development.md, docs/exceptions.md, docs/math.md, docs/setup.md, docs/testing.md) are updated to reflect the new source path, the new error class names, the new requirement of Node 26, the new test files, and the new web/ workflow.
  • docs/api.md is regenerated via npm run docs to include the bweight and surface exports and the Section 6.3 boundary-weight cascade.
  • Bump dev-dependency group to current latest:
    • @rollup/plugin-node-resolve ^16.0.1 → ^16.0.3
    • jsdoc-to-markdown ^9.1.1 → ^9.1.3
    • mocha ^11.8.0 → ^12.0.0
    • The rest of the dev deps (@rollup/plugin-commonjs, @rollup/plugin-terser, rollup, c8, chai, sinon, standard) were already at latest.
  • Bump GitHub Actions: actions/checkout and actions/setup-node to v8.
  • Tighten the StandardJS ignore list to also skip web/ (the playground is type-checked with tsc and linted with next lint rather than StandardJS).
  • Section 6.3 tent μ fix (line 1559 / eq. 6.21): μ is 1 at each face barycenter and 0 on every face boundary (edges / vertices), piecewise affine on the Alfeld-split sub-triangles — the globally-continuous paper definition — instead of the reverse vertex-valued tent.
  • Use the paper's μ_σ = χ_{es_∂(σ)} μ (barycenter tent on the boundary-extended star) in the vertex boundary weight ζ_{0,v}^0, replacing the vertex tent; the dual property (ζ, v^0, u) = u(v) (eq. 6.25) is preserved.
  • Enforce the mean-zero constraint in Solver with an exact Lagrange-multiplier (bordered) solve instead of row replacement, so every stiffness row is honored.
  • Use a single mesh-orientation normal flux for all H(div) faces with Whitney-basis sign alignment, giving a continuous normal trace across interior faces.
  • Fall back to the cell mean (never a silent zero) when a higher-order L² mass matrix solve is singular.
  • Evaluate the H¹ boundary DoF exactly at the vertex u(v) (eq. 6.25) instead of approximating the weighted surface integral.
  • Use the exact edge DoF ∫_e u·t ds on every H(curl) edge, interior included, instead of midpoint tangential sampling.
  • Source files renamed to single-word names: math_utils → utils, local_solver → solver, boundary_weight_computer → weight, higher_order_projection → bubble, mesh_refinement → refinement, mesh_generator → generator, point_locator → locator, convergence_harness → harness, projectors/*_projector → projectors/h1|hcurl|hdiv|l2.
  • Classes renamed to single words: TraceProjector → Projector, H1Projector → H1, HcurlProjector → Hcurl, HdivProjector → Hdiv, L2Projector → L2, BoundaryWeightComputer → Weight, LocalSolver → Solver, HigherOrderProjection → Bubble, MeshRefinement → Refinement, PointLocator → Locator, MeshValidationError → ValidateError, ProjectionError → ProjectError, SingularMatrixError → SingularError.
  • Plain public member names for every field and method; no #private markers and no leading-underscore semi-private prefixes.
  • Package export subpaths renamed (./utils, ./locator) and the PointLocator / buildPointLocator API to Locator / buildLocator.
  • Fix case-sensitivity bug in tests importing traceProjector.js (now traceprojector.js).
  • Restructure README header with centered layout and aligned badges.
  • Rename package from bcdtpp to traceprojector (the public class was Bcdtpp at the time, later renamed to TraceProjector, and finally to Projector).
  • Remove the obsolete Weight.computeVertexWeights Solver / nodeMap route and the now-dead vertexBoundaryData / Projector.vertexData (the H¹ boundary DoF is exact u(v)). Drop the unused meshRefinement constructor argument from Weight, and drop the now-dead Weight fault isolation coverage tests.

#Changed (BREAKING)

  • Source tree moved from src/lib/ to traceprojector/. The src/ wrapper is gone — the package now ships with the source living in a top-level traceprojector/ directory, so the package name and the directory name match exactly and the layout is obvious from the repo root. package.json (main, module, unpkg, jsdelivr, every exports.*, types, files), the docs script glob, the rollup input, the architecture.md module map, the math.md cross-references, the setup.md / testing.md / development.md examples, the README, and every tests/*.test.js import are updated. The internal layout of the package is preserved, so relative imports inside the package still resolve.
  • Babel is removed from the build pipeline. @babel/core, @babel/preset-env, @rollup/plugin-babel, and babel.config.json are deleted: the project is pure ESM and only ever runs on Node 26+, so the Babel pass was a no-op.
  • Pin to Node 26. The CI matrix is reduced from [20, 22] to a single Node 26 job, and the publish.yml workflow is updated accordingly. docs/setup.md requirements are bumped to Node 26, npm 11. A new web CI job compiles the Next.js playground.
  • Repository URL is updated to https://github.com/sachncs/traceprojector in package.json (homepage, repository.url, bugs.url), every README badge, the CI workflow URLs (implicit), and the docs/setup.md install instructions. The historical commit links in the changelog still point at the original bounded-commuting-discrete-trace-preserving-projections repo because they reference real past commits.
  • Error class names in docs: MeshValidationError → ValidateError, ProjectionError → ProjectError, SingularMatrixError → SingularError (the class names in source were already renamed earlier in this release; this just brings the docs in line).

#0.0.7 — 2026-06-20

  • Add comprehensive test suite: interior projector, convergence harness, local solver, mesh generator, point locator, Whitney basis, quadrature, coverage edge cases
  • Add convergence test framework (h-refinement and p-refinement on all four form degrees)
  • Add mesh generator for cube subdivision
  • Add PointLocator AABB tree for O(log N) point-in-tet queries
  • Add LocalSolver with surface stiffness assembly and constrained solve
  • Add BoundaryWeightComputer for trace-preserving projection weights
  • Implement Worsey-Farin split (§6.1.4) with idempotency
  • Implement Alfeld split (§6.1.3) with idempotency
  • Fix UMD global name to TraceProjector in rollup config
  • Fix linting issues across all source files

#0.0.6 — 2026-05-12

  • Add Mesh class with topology (faces, edges, boundary), geometry (volume, normals), and adjacency
  • Add Whitney class for barycentric coordinates and Whitney finite-element basis functions
  • Add math utilities: LU solver, 3x3 inverse, numerical gradient, vector operations
  • Add higher-order projection framework (§7) with bubble corrections
  • Add L2 projector (l=3) for piecewise constants
  • Add MeshRefinement class for Alfeld/Worsey-Farin splits
  • Fix orientation sign computation for edges and faces
  • Fix tetDeterminant (scalar triple product) and add tetVolume
  • Refactor projectors into separate files under src/lib/projectors/

#0.0.5 — 2026-05-12

  • Add H(curl) projector (l=1) for Nédélec first-kind (Whitney 1-form) space
  • Add H(div) projector (l=2) for Raviart-Thomas (Whitney 2-form) space
  • Implement interior projector Π_ring^l and discrete extension operator E^l
  • Implement boundary correction part Π_partial^l
  • Implement global projector decomposition: Π^l = Π_partial^l + Π_ring^l (I − Π_partial^l)
  • Add computeBoundaryWeights for trace-preserving projections

#0.0.4 — 2026-05-05

  • Add H1 projector (l=0) for continuous piecewise-linear space
  • Implement boundary-aware projection with vertex weights
  • Add projectAtPoint convenience method with AABB point locator
  • Add extractBoundaryDofs for boundary degree-of-freedom extraction

#0.0.3 — 2026-05-05

  • Add TraceProjector main class with project method dispatching to form degree l
  • Add basic error classes: MeshValidationError, ProjectionError, SingularMatrixError
  • Implement first version of H1 projection
  • Add rollup UMD bundle configuration

#0.0.2 — 2026-05-04

  • Add Mesh class with tetrahedral mesh construction and validation
  • Add Whitney class with barycentric coordinates and edge/face basis functions
  • Add math utilities: dot, cross, norm, subtract, matrix operations
  • Add Gaussian quadrature for triangles, tetrahedra, and lines
  • Add Mocha/Chai test infrastructure

#0.0.1 — 2026-05-03

  • Initial project setup with npm, StandardJS, Mocha/Chai, c8 coverage
  • Add README, CONTRIBUTING, LICENSE, and project configuration
  • Add GitHub Actions CI workflow
  • Add documentation: architecture, math background, setup, testing, publishing

#Dependency Updates

#2026-07-07

  • Merge pull request #1 — Bump actions/checkout from 4 to 7
  • Merge pull request #2 — Bump actions/setup-node from 4 to 6
  • Merge pull request #3 — Bump dev-dependencies group (4 updates)
  • Merge pull request #4 — Bump chai from 5.3.3 to 6.2.2
  • Merge pull request #5 — Bump c8 from 10.1.3 to 11.0.0
  • Merge pull request #6 — Bump @babel/preset-env from 7.29.5 to 8.0.2
  • Merge pull request #7 — Bump @babel/core from 7.29.0 to 8.0.1