For ADW (AI Developer Workflow) agents working on the particula repository.
Name: particula
Description: A simple, fast, and powerful particle simulator
Language: Python 3.12+
Repository: https://github.com/Gorkowski/particula.git
Version: 0.2.6
# Run all tests
pytest
# Run tests with coverage
pytest --cov=particula --cov-report=term-missing
# Run linters (auto-fix)
ruff check particula/ --fix
ruff format particula/
ruff check particula/
# Run type checker
mypy particula/ --ignore-missing-imports
# Slow + performance benchmarks (excluded from CI)
pytest particula/dynamics/condensation/tests/staggered_performance_test.py -v -m "slow and performance"
# ADW tools
.opencode/tool/run_pytest.py # Run tests with validation
.opencode/tool/run_linters.py # Run linters following CI workflowPerformance benchmarks verify O(n) scaling at 1k/10k/100k particles, theta-mode comparisons (half/random/batch), and deterministic seeds. Note: staggered uses Gauss-Seidel per-particle loops (sequential), so high overhead vs simultaneous (vectorized) is expected and not enforced as a target.
# Development installation
pip install -e .[dev]
# Or with uv
uv pip install -e .[dev]- Functions/Variables:
snake_case(e.g.,calculate_density,molar_mass_ratio) - Classes:
PascalCase(e.g.,Aerosol,AerosolBuilder) - Constants:
UPPER_CASE(e.g.,BOLTZMANN_CONSTANT,GAS_CONSTANT) - Modules:
snake_case(e.g.,activity_coefficients.py) - Test files:
*_test.pysuffix (e.g.,activity_coefficients_test.py)
- Line length: 80 characters
- Indentation: 4 spaces (never tabs)
- Docstrings: Google-style
- String quotes: Double quotes
" - Import order: stdlib → third-party → local
from typing import Union
from numpy.typing import NDArray
import numpy as np
def function(
mass: Union[float, NDArray[np.float64]],
volume: Union[float, NDArray[np.float64]],
) -> Union[float, NDArray[np.float64]]:
"""Short description."""
return mass / volumeFramework: pytest
Coverage: pytest-cov
Minimum tests: 500 (current: 711)
Test pattern: *_test.py
Test structure:
particula/
├── activity/
│ ├── tests/
│ │ ├── activity_coefficients_test.py
│ │ └── ...
│ └── activity_coefficients.py
└── ...
Linters: ruff (check + format), mypy
CI Workflow:
ruff check particula/ --fix(apply fixes)ruff format particula/(format code)ruff check particula/(final check - must pass)
Configuration: See pyproject.toml → [tool.ruff]
Test files: Assertions allowed (S101 ignored in *_test.py)
particula/
├── activity/ # Activity coefficients, phase separation
├── dynamics/ # Coagulation, condensation, wall loss
│ ├── coagulation/
│ ├── condensation/
│ └── properties/
├── equilibria/ # Partitioning calculations
├── gas/ # Gas phase, species, vapor pressure
│ └── properties/
├── particles/ # Particle distributions, representations
│ ├── distribution_strategies/
│ └── properties/
├── util/ # Utilities, constants, validation
│ ├── chemical/
│ └── lf2013_coagulation/
├── integration_tests/ # Integration tests
└── __init__.py
Location: adw-docs/
Key guides:
adw-docs/testing_guide.md- Test framework and conventionsadw-docs/linting_guide.md- Linting tools and configurationadw-docs/code_style.md- Naming, formatting, type hintsadw-docs/docstring_guide.md- Google-style docstring formatadw-docs/commit_conventions.md- Commit message formatadw-docs/pr_conventions.md- Pull request conventionsadw-docs/architecture/architecture_guide.md- Module structure
from particula.util.validate_inputs import validate_inputs
@validate_inputs({
"mass": "positive",
"volume": "positive",
})
def calculate_density(mass: float, volume: float) -> float:
"""Calculate density."""
return mass / volumeAvailable validators: "positive", "nonnegative", "finite"
"""Short description of module purpose.
Optional longer description or citation:
Author, A. B., & Author, C. D. (2019).
Paper title.
Journal Name
https://doi.org/...
"""def function(arg1: float, arg2: str) -> bool:
"""Short one-line summary.
Optional longer description.
Args:
arg1: Description of arg1.
arg2: Description of arg2.
Returns:
Description of return value.
Raises:
ValueError: When arg1 is negative.
"""
passimport particula as par
strategy = par.dynamics.ChargedWallLossStrategy(
wall_eddy_diffusivity=0.001,
chamber_geometry="spherical",
chamber_radius=0.5,
wall_potential=0.05, # V; image-charge still applies when set to 0
wall_electric_field=0.0, # V/m (tuple for rectangular geometry)
distribution_type="discrete",
)
wall_loss = par.dynamics.WallLoss(wall_loss_strategy=strategy)
# Split time_step across sub_steps; concentrations clamp at zero each step
aerosol = wall_loss.execute(aerosol, time_step=1.0, sub_steps=2)Key points:
- Strategies live in
particula.dynamics.wall_lossand are exported throughparticula.dynamics. WallLossStrategyis the abstract base class for wall loss models.WallLossrunnable wraps a strategy, splitstime_stepacrosssub_steps, clamps concentrations to non-negative, and composes with other runnables via|.ChargedWallLossStrategyadds image-charge enhancement (active even whenwall_potentialis 0), optionalwall_electric_fielddrift, and falls back to the neutral coefficient when particle charge and field are zero.- Use
ChargedWallLossBuilderwithset_chamber_geometryplusset_chamber_radiusorset_chamber_dimensions, andset_wall_potential/set_wall_electric_field;WallLossFactorysupportsstrategy_type="charged". - Supported
distribution_typevalues are"discrete","continuous_pdf", and"particle_resolved".
Available workflows:
adw workflow list # List all workflows
adw workflow complete 123 # Full workflow for issue #123
adw workflow patch 456 # Quick patch for issue #456
adw workflow test # Run tests only
adw workflow document # Update documentationWorkflow phases:
- plan - Create implementation plan
- build - Implement changes
- lint - Run linters (auto-fix)
- test - Run tests (min 500 required)
- review - Code review
- document - Update docs
- ship - Create PR
Configuration:
pyproject.toml- Package config, ruff, pytest.github/workflows/test.yml- Test CI.github/workflows/lint.yml- Lint CI.pre-commit-config.yaml- Pre-commit hooks
ADW Tools:
.opencode/tool/run_pytest.py- Test runner with validation.opencode/tool/run_linters.py- Linter runner following CI workflow
Core:
- numpy >= 2.0.0
- scipy >= 1.12
Development:
- pytest (testing)
- ruff (linting + formatting)
- mypy (type checking - optional)
- mkdocs, mkdocs-material (documentation)
- Scientific Computing: Use NumPy for vectorized operations
- Validation: Use
@validate_inputsdecorator for public functions - Testing: Maintain >500 tests, use
*_test.pypattern - Documentation: Google-style docstrings with citations
- Code Quality: Ruff (check + format) + mypy
- Line Length: 80 characters max
- Type Hints: Required for public APIs
Before committing:
# Run linters
ruff check particula/ --fix && ruff format particula/ && ruff check particula/
# Run tests
pytest --cov=particula
# Or use ADW tools
.opencode/tool/run_linters.py && .opencode/tool/run_pytest.pyNotebooks in docs/Examples/ use Jupytext paired sync. Edit .py files, not .ipynb:
# 1. Edit the .py file (percent format with # %% cell markers)
# 2. Lint the .py file
ruff check docs/Examples/path/to/file.py --fix
ruff format docs/Examples/path/to/file.py
# 3. Sync to update .ipynb
python3 .opencode/tool/validate_notebook.py docs/Examples/path/to/file.ipynb --sync
# 4. Execute to validate and generate outputs
python3 .opencode/tool/run_notebook.py docs/Examples/path/to/file.ipynb
# 5. Commit both files (.py and .ipynb)Key points:
- Always edit
.pyfiles, not.ipynbdirectly - Lint before sync to catch syntax errors
- Execute after sync to validate code and generate website outputs
- Commit both files to keep them paired
Full documentation: adw-docs/documentation_guide.md (Jupytext Paired Sync Workflow section)
Documentation:
- Full guides:
adw-docs/ - Examples:
docs/Examples/ - Theory:
docs/Theory/
ADW Commands:
adw health # Check ADW system health
adw status # Show active workflows
adw workflow list # List available workflowsLast Updated: 2026-01-30
For questions about ADW: See adw-docs/README.md
For questions about particula: See main readme.md