Contributing¶
Development Setup¶
git clone https://github.com/DanaResearchGroup/AdsPro.git
cd AdsPro
python3 -m venv ~/adspro-venv
source ~/adspro-venv/bin/activate
pip install -r requirements.txt
pip install -e .
Running the Test Suite¶
# All 95 tests
python3 -m pytest tests/ -v
# With coverage report
python3 -m pytest tests/ --cov=adspro --cov-report=term-missing
# Single module
python3 -m pytest tests/test_pmf_calculator.py -v
Test Modules¶
| File | Module | What it covers |
|---|---|---|
test_config_manager.py |
config_manager.py |
Config parsing, validation, Debye length, n_runs |
test_grainer.py |
grainer.py |
CG geometry, Henderson-Hasselbalch, Lysozyme graining |
test_surface_builder.py |
surface_builder.py |
Fibonacci sphere, Grahame equation, ZetaSurface |
test_energy_calculator.py |
energy_calculator.py |
Gō energy, SASA, internal energy |
test_pmf_calculator.py |
pmf_calculator.py |
WHAM keys, flat potential, edge cases |
test_bond_detector.py |
bond_detector.py |
Bond energy function, charge classification |
test_reporter.py |
reporter.py |
Output file generation smoke tests |
test_runner.py |
runner.py |
_select_best_run: median selection, NaN handling |
test_validator.py |
validator.py |
Tilt angle, native contact retention, surface distances |
test_physics_engine.py |
physics_engine.py |
Velocity-Verlet integration, Langevin forces |
test_cache_manager.py |
cache_manager.py |
Caching logic |
Linting with Ruff¶
AdsPro uses Ruff for linting and style checking.
pip install ruff
# Check
ruff check adspro/
# Fix automatically where possible
ruff check adspro/ --fix
Ruff is configured in pyproject.toml:
[tool.ruff]
line-length = 100
target-version = "py39"
[tool.ruff.lint]
select = ["E", "F", "W"]
ignore = ["E501"]
Validating Code Changes¶
Important
When modifying any module (physics_engine, energy_calculator, pmf_calculator, runner), always validate by running a short simulation before committing:
source ~/adspro-venv/bin/activate
# Quick validation run (reduce steps for speed)
python -m adspro --project example --log-level DEBUG
Check the output for: - WHAM converges - ΔG_ads is in the range −10 to −50 kJ/mol for Lysozyme on silica - No Python exceptions or warnings
CI Pipeline¶
The CI runs on every push and pull request to main:
- Ruff — linting on Python 3.11
- Tests — pytest on Python 3.9, 3.10, 3.11
- Coverage — uploaded to Codecov (Python 3.11 only)
- Docs — MkDocs deployed to GitHub Pages (main branch only)
Module Architecture¶
adspro/
├── __main__.py # CLI entry point (argparse)
├── config_manager.py # YAML parsing, validation, defaults
├── grainer.py # PDB → CG beads (Henderson-Hasselbalch charges)
├── surface_builder.py # Fibonacci sphere, Grahame equation, Debye length
├── physics_engine.py # Velocity-Verlet Langevin MD, force evaluation
├── energy_calculator.py # Morse, Gō, SASA, internal energy computations
├── bond_detector.py # Non-covalent bond inventory (H-bonds, salt bridges)
├── orientation_sampler.py # Phase 0: rigid-body SO(3) sampling + protected orientations
├── pmf_calculator.py # WHAM self-consistent iteration
├── runner.py # Pipeline orchestration: Phase 0 → 1 → 2, smart window
├── reporter.py # Write summary_report.txt, summary.json, pmf_result.json
├── validator.py # Tilt angle, contact retention, COM distance
└── visualizer.py # Three.js HTML viewer generation
Data Flow¶
runner.py
├── grainer.py → CG protein
├── surface_builder.py → NP surface beads
├── bond_detector.py → initial bond inventory
├── energy_calculator.py → initial energy baseline
├── orientation_sampler.py → Phase 0 screening
├── physics_engine.py → Phase 1 Langevin MD
├── physics_engine.py → Phase 2 steered MD
├── (smart window detection)
├── physics_engine.py → Phase 2 umbrella windows
├── pmf_calculator.py → WHAM → G(ξ) → ΔG_ads
├── validator.py → observables
├── bond_detector.py → final bond inventory
├── reporter.py → output files
└── visualizer.py → HTML viewer
Extending AdsPro¶
Adding a New Surface¶
See Extending to New Surfaces for the full protocol.
Adding a New Observable¶
- Implement the computation in
validator.py - Add the result to the
summarydict inrunner.py - Write it to
summary.jsoninreporter.py - Add a test in
tests/test_validator.py
Adding a New Force Term¶
- Implement
_f_<name>inphysics_engine.py - Add it to the
_total_forcecall inrun_phase1andrun_umbrella_window - Add a test in
tests/test_physics_engine.py - Validate with a simulation run
Reporting Issues¶
Open an issue on GitHub with:
- AdsPro version
- Python version and OS
- The config.yaml you used
- The full terminal output (use --log-level DEBUG)
- The summary_report.txt if the run completed