Continuum simulation of biological nanopores, in open-source Python.
nanopnp implements the ePNP-NS framework of Willems et al., Nanoscale 12, 16775–16795
(2020) (10.1039/D0NR03114C), and replaces a COMSOL
Multiphysics workflow. You give it a pore geometry, an electrolyte and an applied bias. It solves
the extended Poisson–Nernst–Planck / Navier–Stokes equations at steady state on a 2D-axisymmetric
finite-element mesh, and returns the ionic current and conductance, the transport numbers, the
current rectification and the electro-osmotic flow rate. Every result carries a provenance manifest
that can reconstruct the run.
- The validated model, and its ablations. The ePNP-NS corrections to the diffusivity, mobility,
permittivity, viscosity and density can each be switched independently. Their fitted parameters
live in versioned data files, not in code. Classical PNP-NS is a configuration, not a branch,
and
pnp,poisson,pbandpb-linearare separate named models. - Numbers you can trust or none at all. The ionic current is extracted by two independent routes, and their agreement is checked before any value is returned. Concentration positivity, packing fraction and mesh element quality are all gated. A failed gate aborts with the gate, the quantity and its location, never with a plausible wrong answer.
- Hard cases by continuation. A staged ladder, warm-started from rung to rung, reaches high salt and high bias rather than relying on a cold solve.
- Reproducible by construction. A case file (
nanopnp/case/v0.5) is the unit of work. Every stage emits a content-hashed artefact, and every run records its inputs, library versions, solver settings, stabilisation mode and every switch set away from the validated default.nanopnp reproducere-solves a run and checks every number. - Sweeps and clusters. Any case field can be swept. Each point is an independent job that starts from a converged neighbour, so a sweep maps directly onto an HPC job array.
- Three ways in. The
nanopnpcommand line, a Python API of twenty stable names, and a PySide6 desktop shell with live convergence plots and a field viewer. - Comparable with the reference. A reference-matching stabilised mode, and a Tier-3 comparison against the paper's published current–voltage relationships and in-pore averages.
Pre-alpha. The solver core, the case file, the command line, parameter sweeps, provenance, a
desktop shell, and the user documentation with seven worked examples are implemented and tested.
Meshes are supplied from outside, generated for an idealised pore or the ClyA reference geometry,
or built from a PDB structure by the geometry pipeline (Phase 2). Fixed charge is supplied as a
field, or protonated with PDB2PQR and PROPKA and deposited on the mesh by the charge pipeline
(Phase 3, v0.4). Nothing is a validated release yet. The comparison against the paper's published results gates v0.7.
The case schema and the Python API may still change until the stable v1.0 (SPECIFICATION.md §8.2.6 F4).
| Release | Phase | Scope | State |
|---|---|---|---|
| v0.1 | 0 | Spike: the coupled model on an analytic pore, the continuation ladder, analytic benchmarks | released, v0.1.0 |
| v0.2 | 1 | Solver core: external meshes and fields, QoI extraction, frozen case schema, API, CLI, sweeps | released, v0.2.0 |
| v0.3 | 2 | Geometry pipeline from a PDB structure: alignment, density, symmetry reduction, contour, mesh | released, v0.3.0 |
| v0.4 | 3 | Charge pipeline: PDB2PQR charges, smeared fixed charge and dielectric; the paper's pipeline end to end | released, v0.4.0 |
| v0.5 | 4 | Polish and user testing: the architecture's modularity explored, then the physics, numerics, API and CLI tested by a user | planned |
| v0.6 | 5 | Graphical interface: a design and requirements document with mockups, then the desktop application | planned |
| v0.7 | 6 | Validated release: the published results reproduced, V&V suite in CI, tutorials, JOSS submission, DOI archive | planned |
| v1.0 | — | Stable release: the API stability promise; its content is the author's to define | planned |
Each merged work package is tagged vX.Y.Z-alpha.N toward its phase's release, and the package
version is derived from the tag. The history is in CHANGELOG.md, and the full
release plan is in SPECIFICATION.md §2.7 and §8.
nanopnp is not on PyPI yet; that comes with v0.7. Install it from source with
uv:
git clone https://github.com/willemsk/nanopnp.git
cd nanopnp
uv sync --all-extrasClone the full history rather than --depth 1: the version is read from the nearest git tag. The
default install is the solver core and uses binary wheels only. The extras add:
| Extra | Adds |
|---|---|
gui |
The PySide6 desktop shell, nanopnp-gui |
examples |
Matplotlib, for the worked examples' plots |
structure |
The structure-to-mesh pipeline's dependencies (v0.3), and PDB2PQR for the charge pipeline (v0.4) |
gmsh |
The optional gmsh mesher backend (GPL-2+, never on the default path) |
A VS Code Dev Container and a GitHub Codespace configuration are in
.devcontainer/ if you would rather not install anything locally.
This is example 01:
cd examples/01-quickstart
uv run nanopnp run quickstart.case.yaml --store store --run-dir run
uv run nanopnp inspect run
uv run nanopnp reproduce runIt meshes an idealised pore, solves the validated ePNP-NS model on it, reads the run's provenance back, and re-solves it to check that every number reproduces. The worked examples go on to a charged pore, an I–V sweep, the Python API, the ClyA reference geometry on a cluster, and a PDB entry taken to a mesh and then to a charged run.
To run the test suite: uv run pytest. To build the documentation: uv sync --all-extras --group docs && uv run docs/scripts/generate.py && uv run mkdocs build --strict (uv sync is exact, so
naming only --group docs would uninstall the extras).
The documentation covers a user guide, the five worked examples, and generated case-file,
command-line and API references. It is built from docs/ with MkDocs and will be hosted at
nanopnp.readthedocs.io once that project is connected. The
model pages render the specification and the knowledge base verbatim.
| Path | Content |
|---|---|
SPECIFICATION.md |
Requirements, physics, design, numerics and V&V plan |
CHANGELOG.md |
Every tagged version, and what each work package delivered |
knowledge/ |
Verified knowledge base: physics, numerics, biology, tooling |
examples/ |
Five worked examples, each executed by a test |
docs/ |
The documentation site's sources (mkdocs.yml at the root) |
data/corrections/ |
Fitted correction parameters, one file per electrolyte |
docs/validation/ |
The COMSOL field-comparison surface, kept but not required: the frozen cases, the probe grid, and the export contract |
packaging/ |
The desktop bundle: its PyInstaller recipe and its licence notice |
CONTRIBUTING.md |
How to report a finding, set up, and get a change accepted |
CLAUDE.md |
Working instructions for coding agents and new contributors |
If you use nanopnp, please cite both the software and the paper it implements. GitHub's
Cite this repository reads the software citation from CITATION.cff. The
paper is:
@article{willems2020accurate,
title = {Accurate modeling of a biological nanopore with an extended continuum framework},
author = {Willems, Kherim and Rui{\'c}, Dino and Lucas, Florian L. R. and Barman, Ujjal and
Verellen, Niels and Hofkens, Johan and Maglia, Giovanni and Van Dorpe, Pol},
journal = {Nanoscale},
volume = {12},
pages = {16775--16795},
year = {2020},
doi = {10.1039/D0NR03114C}
}See CONTRIBUTING.md. Findings are more welcome than fixes. If a benchmark
disagrees with a known answer, or two extraction routes disagree with each other, please open a
Verification finding issue. That is evidence, and it is worth more than a green test suite.
Participation is under the Code of Conduct.
BSD-3-Clause. See LICENSE and CITATION.cff.
The desktop bundle is a different matter: its default direct linear solver is SuiteSparse
UMFPACK, which is GPL-2+ and ships inside the NGSolve wheel, so the bundle as a whole is
distributed under GPL-2+ while the library stays BSD-3. See
packaging/LICENSES-BUNDLE.md, which travels with every bundle.