Metadata-Version: 2.4
Name: octp-pp
Version: 0.1.3
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Chemistry
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Rust
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Dist: numpy>=1.20
Requires-Dist: pandas>=1.3
Requires-Dist: scipy>=1.11
Requires-Dist: plotly>=5.0
Requires-Dist: uncertainties>=3.0
Requires-Dist: openpyxl>=3.0
Requires-Dist: h5py>=3.0
Summary: Post-processing toolkit for OCTP LAMMPS molecular-dynamics output
Keywords: lammps,molecular-dynamics,octp,transport-properties,post-processing,diffusion,conductivity
Author-email: "V. Jelle Lagerweij" <v.j.lagerweij@tudelft.nl>
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Bug Tracker, https://github.com/JelleLagerweij/octp-pp/issues
Project-URL: Repository, https://github.com/JelleLagerweij/octp-pp

# octp-pp

Post-processing toolkit for **OCTP** (Order-n Transport Properties) output files from [LAMMPS](https://www.lammps.org/) molecular dynamics simulations.

The computationally intensive work — file parsing, MSD fitting, and all physical-property models — is compiled to native code via a [PyO3](https://pyo3.rs/)/[maturin](https://www.maturin.rs/) Rust extension. Interactive visualisations use [Plotly](https://plotly.com/python/).

## Features

- **Rust core** — parsing, diffusivity fitting, Laliberte density/viscosity, Dewane and Gilliam conductivity models, and concentration conversions all run natively; the Brent–Dekker molarity→molality inversion is ~570× faster than an equivalent `scipy.fsolve` loop
- **Automatic run averaging** — pass a list of parallel-run folders; means and standard deviations are computed automatically
- **Biased Random Walk (BRW) correction** — built-in correction for proton-hopping contributions (OH⁻ / H₃O⁺) matched against experimental conductivity
- **Configurable constants** — ion charges, molecular weights, hop distance, etc. live in a JSONL file and can be overridden at runtime without touching code

## Installation

```bash
pip install octp-pp
```

### From source

```bash
git clone https://github.com/JelleLagerweij/octp-pp
cd octp-pp
pip install maturin
maturin develop            # debug build  (fast compile, slower runtime)
maturin develop --release  # release build (slow compile, fast runtime)
```

> `maturin build` (and `pip install .`) always use the release profile.
> `maturin develop` defaults to debug — ideal during active development.

## Quick start

```python
import octp_pp as octp
import octp_pp.helpers as hf

# Five parallel NVT runs stored under data/run_1 … data/run_5
mixture = octp.PP_OCTP(
    "data",
    [f"run_{i}" for i in range(1, 6)],
    groups=["wat", "Na", "OH", "SCN"],
    dt=2,           # timestep in fs
    plotting=True,  # interactive Plotly figures
)

# Configure non-default file names (if needed)
mixture.filenames(Diff_Onsag="diffonsag.dat", Diff_self="diffself.dat")
mixture.changefit(Minc=7, Mmax=45, er_max=0.05)

# State properties
mixture.density()
mixture.molality("OH",  "wat", hf.MOLECULAR_WEIGHTS["WAT"])
mixture.molality("SCN", "wat", hf.MOLECULAR_WEIGHTS["WAT"])

# Transport properties
mixture.viscosity()
mixture.self_diffusivity(YH_correction=True)
mixture.onsager_coeff()

# Conductivity
octp.cond_NE(mixture,  ion_names=["Na", "OH", "SCN"], ion_charges=[1, -1, -1])
octp.cond_Ons(mixture, ion_names=["Na", "OH", "SCN"], ion_charges=[1, -1, -1])

# BRW correction (requires experimental Excel file)
octp.biassed_random_walk(mixture, "Experiments_total.xlsx")

mixture.store()   # writes postprocessed.csv next to the data folder
```

## Physical-property helpers (`octp_pp.helpers`)

All functions are vectorised and delegate to the Rust core.

| Function | Model | Output |
|---|---|---|
| `statepoint_Laliberte(T, m, salt, fits)` | Laliberte (2004) | density (kg/m³), molarity (mol/L) |
| `viscosity_Laliberte(T, m, salt, fits)` | Laliberte (2007) | dynamic viscosity (Pa·s) |
| `dewane_conductivity(T, m, salt, ...)` | Dewane and Hammer | conductivity (S/m) |
| `KOH_conductivity_Gilliam_combined(T, m, salt, fits)` | Gilliam | conductivity (S/m) |
| `molarity_to_molality(c, T, salt, fits)` | Brent–Dekker root finder | molality (mol/kg) |
| `molality_to_mass_fraction(m, salt)` | exact | mass fraction |
| `mass_fraction_to_molality(w, salt)` | exact | molality (mol/kg) |
| `molality_to_mol_fraction(m, solvent)` | exact | mole fraction |
| `mol_fraction_to_molality(x, solvent)` | exact | molality (mol/kg) |
| `tau_calculator(sig_exp, sig_MD, T, L, N, δ)` | Lagerweij | lifetime τ (s) |
| `diffusion_adjustment(tau)` | Lagerweij | D_hop (m²/s) |

Fit parameters are stored in a user-provided JSON file (see `test/fits_laliberte.json` for the expected structure).

### Global constants

Loaded from `octp_pp/constants.jsonl` at import time. Override at runtime without editing any file:

```python
# Add a custom salt for this session
hf.load_constants(updates={"MOLECULAR_WEIGHTS": {"MYMAT": 123.45}})

# Inspect what is loaded
print(hf.MOLECULAR_WEIGHTS)
print(hf.DELTA_HOP)
```

## API reference

### `PP_OCTP` class

| Method | Description |
|---|---|
| `filenames(**kwargs)` | Set LAMMPS output file names |
| `changefit(margin, Minc, Mmax, er_max)` | Tune MSD log-log fitting |
| `check_succesfull(T_min)` | Drop runs shorter than T_min ns |
| `mandatory_properties()` | Volume, box size, temperature, particle counts |
| `pressure(plotting, mov_ave)` | Pressure (Pa) |
| `density()` | Density (kg/m³) from NPT run |
| `molarity(group)` | Molarity (mol/L) |
| `molality(group, solvent, MW_solvent)` | Molality (mol/kg) |
| `viscosity(plotting)` | Shear + bulk viscosity (Pa·s) |
| `thermal_conductivity(plotting)` | Thermal conductivity (W/m/K) |
| `self_diffusivity(YH_correction, ...)` | Self-diffusion coefficients (m²/s) |
| `onsager_coeff(box_size_check, ...)` | Onsager cross-coefficients (m²/s) |
| `coord_number(solvent, ...)` | Coordination number from RDF |
| `bond_angles(start, stop, ...)` | Bond-angle distribution |
| `store(location, name, for_excel)` | Save `results` DataFrame to CSV / Excel |

All optional methods call `mandatory_properties()` automatically if it has not yet been run.

### Module-level functions

| Function | Description |
|---|---|
| `cond_NE(mixture, ion_names, ion_charges)` | Nernst–Einstein conductivity (S/m) |
| `cond_Ons(mixture, ion_names, ion_charges)` | Onsager conductivity (S/m) |
| `biassed_random_walk(mixture, exp_file)` | BRW correction; writes back to `mixture.results` |
| `read(datafile, export)` | Read OCTP MSD file → DataFrame |
| `local_maximum_finder(data, start, n)` | First local maximum in g(r) |


## License

MIT

