Metadata-Version: 2.4
Name: pyminichem
Version: 0.2.0
Summary: Torch-based Python bindings for the minichem Fortran chemistry solver.
Author-email: Cheng Li <chengcli@umich.edu>
License: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/chengcli/pyminichem
Project-URL: Documentation, https://pyminichem.readthedocs.io
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: C
Classifier: Programming Language :: C++
Classifier: Programming Language :: Fortran
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 :: Chemistry
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy
Requires-Dist: pytest
Requires-Dist: torch==2.10.0

# pyminichem

`pyminichem` is a standalone Python package and Torch-based C++ wrapper around
the Fortran `mini_chem` code base. The repository follows the same broad layout
used by `pydisort`, `pyharp`, and `kintera`:

- `src/`: native C, C++, and wrapper code
- `python/`: Python package, pybind11 bindings, and packaged resources
- `patches/`: upstream minichem patch set
- `tests/`: C++ and Python validation

The build flow is:

1. Fetch upstream `mini_chem` with CMake.
2. Apply the same `mini_ch_i_dlsode.f90` patch used by `canoe`.
3. Link the patched Fortran implementation into a thin C shim.
4. Wrap that shim in a Torch-based C++ API.
5. Expose the C++ API to Python with pybind11.

## Build

### CPU build

Use the default GNU toolchain for the CPU-only path:

```bash
cmake -S . -B build-cpu -DBUILD_TESTS=ON
cmake --build build-cpu -j
ctest --test-dir build-cpu -R '^test_minichem.release$' --output-on-failure
```

If you want the editable Python package to use the CPU build, copy the native
library into the package locations and reinstall:

```bash
cp build-cpu/lib/libpyminichem_release.so build/lib/libpyminichem_release.so
cp build-cpu/lib/libpyminichem_release.so python/lib/libpyminichem_release.so
python -m pip install -e .
```

### CUDA/OpenACC build with NVHPC

The CUDA path in this repo uses GNU C/C++ for the Torch wrapper and the NVIDIA
HPC SDK Fortran compiler for the OpenACC minichem backend. Do not use GNU
Fortran with `-DCUDA=ON`: it can link through `libgomp`, but the resulting
build fails at runtime on NVIDIA GPUs with `device type nvidia not supported`.

First put the NVIDIA HPC SDK compilers on `PATH`:

```bash
export NVHPC=/opt/nvidia/hpc_sdk
export NVHPC_BIN=$(find "$NVHPC/Linux_x86_64" \
  -mindepth 3 -maxdepth 3 -path '*/compilers/bin' -type d \
  | sort -V | tail -n 1)
export PATH="$NVHPC_BIN:$PATH"

gcc --version
g++ --version
nvfortran --version
```

Then configure CMake with CUDA enabled. When `-DCUDA=ON`, CMake defaults to
`gcc`, `g++`, and `nvfortran` unless compilers are explicitly provided with
`-DCMAKE_*_COMPILER=...`.

```bash
cmake -S . -B build-nvhpc \
  -DBUILD_TESTS=OFF \
  -DCUDA=ON

cmake --build build-nvhpc -j
```

For a test-enabled local CUDA build:

```bash
cmake -S . -B build-nvhpc \
  -DBUILD_TESTS=ON \
  -DCUDA=ON

cmake --build build-nvhpc -j
ctest --test-dir build-nvhpc -R '^test_minichem.release$' --output-on-failure
```

To make the editable Python package use the NVHPC/CUDA build:

```bash
cp build-nvhpc/lib/libpyminichem_release.so build/lib/libpyminichem_release.so
cp build-nvhpc/lib/libpyminichem_release.so python/lib/libpyminichem_release.so
python -m pip install -e .
```

After installing the editable package, the CUDA example should run with CUDA
tensors:

```bash
python examples/minichem.py
```

For PyPI/release wheels, the Linux `cibuildwheel` job uses
`docker.io/luminoctum/manylinux2_28-cuda12.8-nvhpc:2026-04-28`. That image
already provides CUDA Toolkit and NVIDIA HPC SDK. The release workflow discovers
`/opt/nvidia/hpc_sdk/Linux_x86_64/<version>/compilers/bin`, exports `CC=gcc`,
`CXX=g++`, `FC=nvfortran`, and passes those compilers to CMake.

To avoid installing CUDA/NVHPC during every release build, see
`docs/nvhpc-cuda-manylinux-image.md` for instructions to build a
`manylinux_2_28` image with CUDA Toolkit and NVHPC, then push it to Docker Hub.

## Test

### Python tests

After installing the editable package:

```bash
pytest tests
```

### GPU smoke test

Run the live CUDA test from a directory outside the repo root, so Python imports
the editable package instead of treating the top-level `pyminichem/` repo
directory as a namespace package:

```bash
cd /tmp
python - <<'PY'
import torch
import pyminichem

print('cuda_enabled', pyminichem.cuda_enabled())
print('torch_cuda_available', torch.cuda.is_available())
print('device_count', torch.cuda.device_count())

base_vmr = torch.tensor(
    [[0.0, 0.9975, 0.001074, 0.0, 0.0, 0.0, 0.0, 0.00059024, 0.0, 0.00014159, 0.0, 0.0]],
    dtype=torch.float64,
)

outputs = []
for dev in [0, 1]:
    device = f'cuda:{dev}'
    mc = pyminichem.MiniChem()
    mc.initialize()
    temp = torch.tensor([1500.0], dtype=torch.float64, device=device)
    pres = torch.tensor([1.0e5], dtype=torch.float64, device=device)
    vmr = base_vmr.to(device)
    out = mc.forward(temp, pres, vmr, 60.0)
    torch.cuda.synchronize(dev)
    out_cpu = out.detach().cpu()
    outputs.append(out_cpu)
    print('device', dev, 'out_device', out.device, 'shape', tuple(out.shape))
    print('finite', bool(torch.isfinite(out).all().item()), 'sum', float(out_cpu.sum().item()))

if len(outputs) == 2:
    diff = (outputs[0] - outputs[1]).abs().max().item()
    print('max_abs_diff_between_gpu0_gpu1', diff)
PY
```

Expected behavior for the current working NVHPC build:

- `cuda_enabled True`
- `torch_cuda_available True`
- `device_count 2` on this machine
- finite output tensors on both `cuda:0` and `cuda:1`
- `max_abs_diff_between_gpu0_gpu1 0.0` for the smoke test above

## NVIDIA HPC SDK

For the CUDA/OpenACC build, install the NVIDIA HPC SDK from NVIDIA's official
Linux x86_64 packages:

1. Download the SDK tarball from the NVIDIA HPC SDK download page.
2. Extract the archive.
3. Run the installer.
4. Add the compiler `bin` directory to `PATH`.

Official references:

- OpenACC getting started guide:
  `https://docs.nvidia.com/hpc-sdk/archive/25.3/compilers/openacc-gs/index.html`
- NVIDIA HPC SDK download page:
  `https://developer.nvidia.com/hpc-sdk`

Typical installation flow:

```bash
wget <official-nvhpc-tarball-url>
tar -xpf nvhpc_<version>_Linux_x86_64_cuda_multi.tar.gz
cd nvhpc_<version>_Linux_x86_64_cuda_multi
sudo ./install
```

The default install location is typically:

```bash
/opt/nvidia/hpc_sdk/Linux_x86_64/<version>/compilers/bin
```

Add the compilers to your shell environment:

```bash
export NVHPC=/opt/nvidia/hpc_sdk
export PATH=$NVHPC/Linux_x86_64/<version>/compilers/bin:$PATH
```

Verify the installation with:

```bash
nvfortran --version
nvc++ --version
nvaccelinfo
```

Notes:

- Replace `<version>` with the installed SDK version, for example `25.3`.
- `nvaccelinfo` is NVIDIA's recommended check that the driver and GPU-facing
  toolchain are visible.
- The default `/opt` installation path usually requires `sudo`.
