Metadata-Version: 2.4
Name: plasmacoll
Version: 0.1.0
Summary: Null-collision Monte Carlo collisions of charged particles with neutral gases, on NumPy or CuPy arrays.
Author: Max
License: MIT License
        
        Copyright (c) 2026 Max Lindqvist
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Source, https://github.com/max-models/plasmacoll
Keywords: cross sections,cupy,lxcat,monte carlo collisions,negative ions,null collision,particle-in-cell,plasma
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: cunumpy>=0.5
Requires-Dist: numpy
Provides-Extra: dev
Requires-Dist: jupyterlab; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: pyproject-fmt; extra == "dev"
Requires-Dist: pyright; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: ty; extra == "dev"
Requires-Dist: plasmacoll[docs,test]; extra == "dev"
Provides-Extra: docs
Requires-Dist: griffe; extra == "docs"
Requires-Dist: ipykernel; extra == "docs"
Requires-Dist: matplotlib; extra == "docs"
Requires-Dist: nbclient>=0.11.0; extra == "docs"
Requires-Dist: nbformat>=5.11.1; extra == "docs"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Dynamic: license-file

# plasmacoll


<!-- README.md is generated from README.qmd: edit the .qmd and run `make readme`. -->

[![Tests](https://github.com/max-models/plasmacoll/actions/workflows/test_pytest.yml/badge.svg)](https://github.com/max-models/plasmacoll/actions/workflows/test_pytest.yml)
[![Static
analysis](https://github.com/max-models/plasmacoll/actions/workflows/static_analysis.yml/badge.svg)](https://github.com/max-models/plasmacoll/actions/workflows/static_analysis.yml)
[![Docs](https://github.com/max-models/plasmacoll/actions/workflows/docs.yml/badge.svg)](https://max-models.github.io/plasmacoll/)
[![codecov](https://codecov.io/gh/max-models/plasmacoll/branch/main/graph/badge.svg)](https://codecov.io/gh/max-models/plasmacoll)
[![PyPI](https://img.shields.io/pypi/v/plasmacoll.png)](https://pypi.org/project/plasmacoll/)
[![Python](https://img.shields.io/pypi/pyversions/plasmacoll.png)](https://pypi.org/project/plasmacoll/)

Null-collision Monte Carlo collisions (MCC) of charged particles with
neutral gases, on NumPy or CuPy arrays. It is the collision step of a
particle-in-cell code, or with `ZeroDReactor` a homogeneous reactor for
testing cross-section sets.

- **Processes:** elastic, backscatter (resonant charge exchange),
  excitation, ionization, attachment, detachment and charge transfer,
  against Maxwellian neutral gases that are uniform or have a density
  profile.
- **Cross sections:** from text tables, LXCat files or functions. Also
  Maxwell molecules for benchmarks, and population-weighted mixtures of
  level-resolved tables, e.g. H₂(v) dissociative attachment.
- **Plain arrays:** markers are positions, velocities and weights. Any
  particle container with those plugs in, and
  [cunumpy](https://pypi.org/project/cunumpy/) runs the same code on CPU
  (NumPy) or GPU (CuPy).
- **Validated:** a 0D reactor reproduces the closed-form relaxation,
  growth and decay rates of Maxwell-molecule gases. The tests run on
  NumPy and on a CuPy stand-in, with 100 % combined coverage.

Documentation: <https://max-models.github.io/plasmacoll/>

![Electron, H₂⁺ and H⁻ densities in a 0D reactor against the analytic
growth
rate](https://max-models.github.io/plasmacoll/tutorials/03-ionization-attachment/1.png)

## Install

``` bash
pip install plasmacoll
```

## Example

``` python
import plasmacoll
from plasmacoll.constants import ATOMIC_MASS, ELECTRON_MASS, ev_to_kelvin

argon_mass = 39.95 * ATOMIC_MASS
argon_gas = plasmacoll.NeutralBackground(
    "Ar", density=1e21, temperature=300.0, mass=argon_mass
)

elastic_xs = plasmacoll.CrossSection.constant(1e-19)
ionization_xs = plasmacoll.CrossSection.constant(3e-20, threshold=15.76)
elastic = plasmacoll.CollisionProcess("elastic", "Ar", elastic_xs, energy_frame="lab")
ionization = plasmacoll.CollisionProcess(
    "ionization",
    "Ar",
    ionization_xs,
    energy_frame="lab",
    products={"electron": "e", "ion": "Ar+"},
)

mcc = plasmacoll.MonteCarloCollisions(
    species_masses={"e": ELECTRON_MASS, "Ar+": argon_mass},
    backgrounds=[argon_gas],
    processes={"e": [elastic, ionization]},
    seed=1,
)

temperature = ev_to_kelvin(10.0)
electrons = plasmacoll.ParticleArrays.maxwellian(
    100_000, ELECTRON_MASS, temperature, seed=2
)
reactor = plasmacoll.ZeroDReactor(mcc, {"e": electrons}, volume=1e-6)
history = reactor.run(dt=1e-11, num_steps=500, every=10)
print(history.density["Ar+"][-1], history.collisions["ionization:Ar"][-1])
```

In a particle-in-cell code, call
`mcc.collide(species, positions, velocities, weights, dt)` on arrays, or
`mcc.collide_species({...}, dt)` on your own particle containers. See
[Use in a particle-in-cell
code](https://max-models.github.io/plasmacoll/guides/particle-in-cell/).

plasmacoll does not ship cross-section data. Load tables from
[LXCat](https://lxcat.net) or the literature with
`plasmacoll.read_lxcat` and `CrossSection.from_table`.

## Development

With [uv](https://docs.astral.sh/uv/):

``` bash
make install    # uv sync --extra dev, plus the pre-commit hooks
make test       # pytest with coverage on NumPy
make test-cupy  # the same tests on cunumpy's stand-in for CuPy (no GPU needed)
make coverage   # both runs combined, must be 100 %
make lint       # ruff check, ruff format --check, pyright, ty
```

Commit messages follow [Conventional
Commits](https://www.conventionalcommits.org/).

## Build docs

The documentation in `docs/` is an [Astro](https://astro.build/) +
[Starlight](https://starlight.astro.build/) site: hand-written guides,
the notebooks in `tutorials/` executed and published as pages, and the
API reference generated from the docstrings. It needs Node 22 or newer.

``` bash
make docs-install     # npm packages and the Python docs extra
make docs-notebooks   # execute tutorials/*.ipynb and convert them to pages
make docs-dev         # live preview at http://localhost:4321/plasmacoll/
make docs-build       # the static site in docs/dist
```

`README.md` is rendered from `README.qmd` with
[Quarto](https://quarto.org/): `make readme`.

## Releases

Before merging a release to `main`, update the version in
`pyproject.toml` and `src/plasmacoll/__init__.py`, and add the release
notes to `CHANGELOG.md`. The push to `main` creates a GitHub release
with a `vX.Y.Z` tag and publishes the package to PyPI with trusted
publishing (OIDC). See the [publishing
guide](https://max-models.github.io/plasmacoll/development/publishing/).
