A Python implementation of P1 and P2 finite element methods, residual a posteriori error estimation, and adaptive mesh refinement for a one-dimensional Poisson problem.
The project studies how limited solution regularity affects higher-order finite element convergence, and how adaptive refinement can recover the optimal rate.
We solve
with the manufactured exact solution
and set
The two values of
-
alpha = 10: the solution is smooth, so both P1 and P2 achieve their optimal rates; -
alpha = 5/3: the solution belongs to$H^s(0,1)$ for$s<13/6$ , but not to$H^3$ . P1 retains first-order convergence in the$H^1$ seminorm, while uniform-mesh P2 is limited to a rate near$7/6$ instead of 2.
For the singular case alpha = 5/3, the implementation reproduces the regularity-limited behavior on uniform meshes and the recovery produced by adaptive refinement:
| Method | Mesh strategy | Fitted slope in DOF | Final test point |
|---|---|---|---|
| P1 | uniform | -0.98 | 511 DOF, error 1.21e-3 |
| P1 | adaptive | -0.96 | 37 DOF, error 1.37e-2 |
| P2 | uniform | -1.18 | 1023 DOF, error 3.85e-5 |
| P2 | adaptive | -2.02 | 75 DOF, error 2.31e-4 |
Adaptive refinement recovers the optimal
The code implements the standard cycle
SOLVE -> ESTIMATE -> MARK -> REFINE
using the residual estimator
where
For P1,
The resulting mesh automatically concentrates points close to the singularity at
The global estimator stays above the measured
The project is written in Python with NumPy and SciPy. Both finite element spaces are assembled from their local basis functions on arbitrary one-dimensional meshes:
- P1: linear Lagrange elements;
- P2: quadratic Lagrange elements with one midpoint DOF per element;
- Gaussian quadrature for load vectors, errors, and residual terms;
- sparse global stiffness matrices;
- direct sparse solution with
scipy.sparse.linalg.spsolve; - residual error indicators and fixed-fraction marking;
- element bisection for local refinement.
.
├── src/adaptive_fem/
│ ├── problem.py # exact solution and forcing term
│ ├── fem.py # P1/P2 assembly and finite-element solution object
│ ├── metrics.py # H1 error and residual estimator
│ ├── adaptivity.py # marking, bisection, adaptive loop
│ └── experiments.py # convergence experiments
├── scripts/
│ ├── run_benchmarks.py
│ ├── run_convergence_study.py
│ ├── run_estimator_study.py
│ └── run_mesh_adaptation.py
├── tests/
│ └── test_fem.py
└── figures/
python -m venv .venv
source .venv/bin/activate # Windows: .venv\\Scripts\\activate
pip install -e .
python scripts/run_benchmarks.py
python scripts/run_convergence_study.py
python scripts/run_estimator_study.py
python scripts/run_mesh_adaptation.pyRun the test suite with
python -m unittest discover -s tests -vThe tests check boundary conditions, error reduction under refinement, regularity-limited uniform convergence, adaptive P2 rate recovery, and estimator reliability.
Higher polynomial degree alone does not guarantee its nominal convergence order: the rate is constrained by solution regularity. Adaptive methods redistribute degrees of freedom toward the regions that dominate the error, allowing the higher-order approximation to recover its expected asymptotic behavior.
MIT License. See LICENSE.