Please see instructions in the book.
This repository contains a small framework in galerkin.py for assembling mass/stiffness-like operators and projecting/solving with different polynomial/trigonometric bases and boundary-condition lifts. The code is using classes for reuse of code and clarity, but is kept as simple as possible for educational purposes.
Big picture (architecture)
- Mapping helpers:
map_reference_domain,map_true_domain,map_expression_true_domainconvert points/expressions between the true domain and a basis-specific reference domain; always use these when mixing domains. - Base space:
FunctionSpace(N, domain)defines common behavior: mesh generation, evaluating basis and derivatives, numerical inner products, and a generic mass matrix via numerical quad. - Concrete spaces
LegendreandChebyshevuse orthogonal polynomials on reference(-1, 1);evaluses fastnp.polynomial.legendre.legval/chebvalon mapped coordinates.Trigonometricbase has reference(0, 1)and adds a boundary lift inevalviaself.B.Xl(X);Sinesis implemented,Cosinesis a placeholder.Compositespaces enforce boundary conditions via a liftBand a stencil matrixS, e.g. Dirichlet: ψ_i = Q_i − Q_{i+2}. Mass is assembled asS · M · S^TwhereMis diagonal in the orthogonal basis. Implementations includeDirichletChebyshev(done) and placeholders for Legendre/Chebyshev Neumann and Legendre Dirichlet.
- Boundary lifts:
DirichletandNeumannconstruct an affine or quadratic functionB.xon the physical domain and its reference-evaluatorB.Xl. Solutions are represented as u(x) = Σ û_i ψ_i(x) + B.x. - Weak forms:
BasisFunction,TrialFunction,TestFunctionprovide a tiny domain-specific language (DSL).inner(Trial.diff(k), Test)builds derivative-weighted bilinear forms;assemble_generic_matrixintegrates with proper weights and symmetry.
Key files and examples
galerkin.pyis the only source file and contains:- Example workflows:
test_project,test_convection_diffusion,test_helmholtzshow projection and PDE assembly patterns. - Space definitions and utilities listed above.
- Example workflows:
Developer workflows
- Dependencies: numpy, scipy, sympy. Install them before running.
- Run examples/tests: execute
python galerkin.pyto run the three demo tests in__main__. - Assemble a PDE (pattern):
- Choose space
V = DirichletChebyshev(N, domain, bc)(or similar). - Define trial/test:
u = TrialFunction(V),v = TestFunction(V). - Build operator: e.g.,
A = inner(u.diff(2), v) + inner(u, v). - Build RHS: subtract lift contribution, e.g.,
b = inner(f - (V.B.x.diff(x, 2) + V.B.x), v). - Solve for coefficients:
np.linalg.solve(A, b)(orsparse.linalg.spsolve).
- Choose space
Project conventions and gotchas
- Reference domains: Legendre/Chebyshev map to
(-1, 1); Trigonometric maps to(0, 1). Always map x before polynomial evaluation (evalmethods handle this). - Coefficient lengths: simple spaces use N+1 coefficients; composite spaces expand with stencil
Sof shape(N+1, N+3)and use diagonalMof lengthN+3in the orthogonal basis. - Chebyshev weighting:
inner_productperforms the substitution x = cos(θ) and integrates on[0, π]to handle the weight 1/√(1−x²); do not use uniform quad there. - Derivatives of trigonometric bases: Sine derivative scale is
((j+1)π)^kwith alternating sign for odd k; seeSines.derivative_basis_functionfor the exact pattern. - Boundary lifts:
V.eval(uh, xj)returnsP @ uh + V.B.Xl(X)for spaces with lifts. When formingb, include the differential operator applied toB.xon the RHS, as shown in tests.
Placeholders intentionally left for students (do not remove without intent)
Cosines,DirichletLegendre.basis_function,NeumannLegendre,NeumannChebyshev, and someL2_norm_sq/mass_matrixoverrides areNotImplemented. Mirror the implemented counterparts:- Cosines similar to Sines but with cos(kπx) including the k=0 mode handling and L2 norms.
- Dirichlet/Neumann Legendre/Chebyshev composite spaces follow the stencil S approach used in
DirichletChebyshevand lifting viaB. - The stencil matrix for the Neumann conditions can be derived using similar logic to the Dirichlet case, ensuring the homogeneous derivative conditions are met at the boundaries. For this use the value of the derivative at the boundary, see lecture 11.
- The demos in
__main__assume these will be implemented; until then, some tests will fail. UseFunctionSpace.mass_matrix()as a generic fallback if you don’t provide a closed-form one.
External APIs and patterns to reuse
- SymPy: build exact expressions and derivatives (
x = sp.Symbol("x")), thensp.lambdifyfor numerical integration and evaluation. - SciPy:
scipy.integrate.quadis used; for Chebyshev, passweight='alg', wvar=(-0.5, -0.5). - Numpy polynomials: prefer
np.polynomial.legendre.legval/chebvalfor fast evaluation of polynomial series.
When adding new spaces or operators
- Subclass
FunctionSpace(orCompositeif enforcing BCs via stencil). Implementbasis_function(j, sympy=False),derivative_basis_function(j, k), optionalweight, andevalif you can use a faster evaluator. - Respect domain mappings and return shapes consistent with
(N+1,)coefficient vectors (or stencil-expanded shapes in composite spaces).