Skip to content

Repository files navigation

SimpleSplines

Stable Dev Build Status Documentation Coverage PkgEval

B-spline finite elements on an interval, built from the Cox-de Boor recursion, with the quadrature and assembly a Galerkin discretisation needs.

The package provides the clamped, periodic and recombined B-spline bases of arbitrary degree on uniform, graded, random or arbitrary meshes; homogeneous Dirichlet, Neumann, Robin, natural and general local boundary conditions per end; tensor products in any number of dimensions, with degree, mesh, domain and boundary condition per axis; and an assembly table from which the mass, stiffness, derivative and variable-coefficient matrices follow as single weighted contractions. Mass solves go through a representation chosen by the basis — an FFT for a periodic uniform basis, a banded Cholesky for a bounded one, and a factored Kronecker product in several dimensions.

It also provides the polar spline space of a mapped disk, where the left radial edge of the parameter rectangle is a pole rather than a boundary. A plain tensor product is discontinuous there; the polar basis replaces the first two radial rows with three functions spanning the constants and linears of a chart at the pole, which makes the space C¹ across it by construction. That space carries its own assembly and a boundary condition on the rim.

It is not a curve- and surface-modelling library: there are no NURBS, no knot insertion, no degree elevation and no least-squares fitting of data. It is for discretising a differential equation and then solving with the result.

Installation

The package is registered in the General registry:

using Pkg
Pkg.add("SimpleSplines")

Example

Solving -u'' = f with u(0) = u(1) = 0, on a cubic basis over 16 uniform cells:

using SimpleSplines

# the boundary condition is built into the basis, not applied to the matrix afterwards
b = BSplineBasis(UniformMesh(16, 0 .. 1), 3, Dirichlet())

# assembly tabulates the basis and its derivatives at the global Gauß-Legendre points,
# and every matrix is a weighted contraction of that one table
q = SplineQuadrature(b)
M = mass_matrix(q)
K = stiffness_matrix(q)

f(x) = π^2 * sin(π * x)
rhs = basis_values(q, 0) * (quadrature_weights(q) .* f.(quadrature_nodes(q)))
û = Matrix(K) \ rhs

maximum(abs(evaluate(b, û, x) - sin(π * x)) for x in range(0, 1; length = 101))

which is 2.08e-6. Fitting a function to the space instead is an L² projection, and the result is callable:

u = Spline(b, l2_projection(q, x -> sin(π * x)))
u(0.5), u(0.5, 1), u(0.0)        # value, first derivative, and the imposed u(0) = 0

The manual has a tutorial, the spline theory the package rests on, a usage page per object with the constructors and the traps, a gallery of nine solved problems with their measured errors, and the full API.

Development

Git hooks

Two hooks live in .githooks. They are not active in a fresh clone — core.hooksPath is local configuration and does not travel with a push — so enable them once per clone:

git config core.hooksPath .githooks

pre-commit acts on staged .jl files only, and exits immediately when a commit stages none, so a documentation- or workflow-only commit is not slowed down by it:

  • JuliaFormatter --check, honouring this repository's own .JuliaFormatter.toml — blocks the commit. Formatting is mechanical and always fixable.
  • fatou lint, when fatou is installed — advisory only, and deliberately so: its unused-import rule does not follow include, so it flags the load-bearing imports of every module file.
  • Unicode NFC — blocks a staged file that is not NFC-normalised. Sources here are NFC, so a file that is not is a regression: a pattern typed in NFC silently matches nothing in a decomposed file, which defeats grep, an editor search and Documenter's doctest comparison alike. Fix with julia --startup-file=no ~/Research/Environment/Harness/githooks/nfc.jl --apply <files>. The invariant is s == Unicode.normalize(s, :NFC), not the absence of combining marks — q̇, v̄ and f̄ have no precomposed codepoint and are two codepoints in NFC as well.
  • using <Package>, which catches a syntax error or a broken include — blocks.

pre-push runs the full test suite with --check-bounds=auto, but only when pushing to main or master; a topic branch is left to CI. It prints nothing for 10–30 minutes, which looks exactly like a network hang and is not one. If you do interrupt it, check for an orphaned Julia process that the killed hook left behind.

Either hook can be bypassed for a single command with --no-verify, for a change you know it does not apply to:

git commit --no-verify
git push --no-verify

The hooks are generated from one shared copy and are byte-identical across the related repositories, so edit them there rather than here — a local edit is silently undone by the next install.

About

A simple implementation of basic splines.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages