Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2e65baa
Add automatic PyTorch to GGML graph export infrastructure
peterspackman Jan 9, 2026
0396ef4
Add bool dtype support and atomistic model input helpers
peterspackman Jan 9, 2026
4896edb
Add C++ graph interpreter and full PET model export pipeline
peterspackman Jan 28, 2026
ed7b7f1
Working forces for graph interpreter
peterspackman Jan 28, 2026
9f7c61f
Before changes
peterspackman Feb 17, 2026
d99941d
Tidy up
peterspackman Feb 17, 2026
3d2efec
Update to deal with dynamic sizes
peterspackman Feb 18, 2026
b89c534
Working torch compile script too
peterspackman Feb 18, 2026
d36a612
Remove upet_get_version_to_load
peterspackman Feb 18, 2026
a8b5c79
Update for new ggml: drop GGML_KQ_MASK_PAD, expand fx_converter ops
peterspackman Apr 14, 2026
d50aa68
Wire WebGPU backend; fix init_constants for non-CPU backends
peterspackman Apr 15, 2026
c2ad8da
Bump ggml tag (WebGPU ACC + backward ops); graph_inference --debug wo…
peterspackman Apr 15, 2026
735ad94
Bump ggml tag (drop WebGPU env-var hacks)
peterspackman Apr 15, 2026
a084a8a
Migrate CLIs to Model interface and BackendProvider
peterspackman Apr 15, 2026
200bb8a
Enable WebGPU in WASM builds (Phase B)
peterspackman Apr 15, 2026
a7e10b2
Expose WebGPU backend to the browser via mlip.js (Phase C+D)
peterspackman Apr 15, 2026
3ba23ab
mdWorker: await every embind call (D2)
peterspackman Apr 15, 2026
04f8553
Migrate website to Svelte + bun, add vibrational-modes demo, L-BFGS, …
peterspackman Apr 15, 2026
72d5f87
Fix missing <cmath> include in graph_interpreter.cpp
peterspackman Apr 15, 2026
6cdff97
ci: switch to graph-format GGUF from HuggingFace, drop legacy converter
peterspackman Apr 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ jobs:
sudo apt-get update
sudo apt-get install -y cmake ninja-build gcc g++ gfortran

- name: Install uv
uses: astral-sh/setup-uv@v7

- name: Cache CPM packages
uses: actions/cache@v4
with:
Expand Down Expand Up @@ -56,12 +53,25 @@ jobs:
- name: Build
run: cmake --build build --config ${{ env.BUILD_TYPE }} -j $(nproc)

# needed for test running
- name: Convert PET-MAD
# Pull a pre-exported graph-format GGUF from HuggingFace and place it
# where the GraphModel tests look for it (build/tests/gguf/pet-auto.gguf).
# Legacy fixed-PET tests skip cleanly when pet-mad.gguf is absent, which
# is the desired behaviour here — CI exercises the graph path only.
- name: Cache graph GGUF
uses: actions/cache@v4
with:
path: build/tests/gguf/pet-auto.gguf
key: gguf-pet-auto-${{ hashFiles('scripts/convert_models.py') }}

- name: Fetch graph GGUF from HuggingFace
run: |
uv run scripts/convert_pet_mad.py --output pet-mad.gguf
rm -f build/tests/pet-mad.gguf
cp pet-mad.gguf build/tests/
mkdir -p build/tests/gguf
if [ ! -s build/tests/gguf/pet-auto.gguf ]; then
curl -fL --retry 3 \
-o build/tests/gguf/pet-auto.gguf \
https://huggingface.co/peterspackman/mlip-gguf/resolve/main/pet-mad-xs.gguf
fi
ls -la build/tests/gguf/

- name: Run tests
working-directory: build
Expand Down
21 changes: 16 additions & 5 deletions .github/workflows/website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ jobs:
with:
node-version: '20'

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install Emscripten
uses: mymindstorm/setup-emsdk@v14
with:
version: '3.1.50'

- name: Install uv
uses: astral-sh/setup-uv@v7

- name: Cache CPM packages
uses: actions/cache@v4
with:
Expand All @@ -44,6 +46,15 @@ jobs:
restore-keys: |
cpm-wasm-

# Cache the bundled GGUF across runs so we don't re-download from HF on
# every build. Keyed on the URL + filename so a model bump in
# package.json invalidates the cache automatically.
- name: Cache bundled GGUF
uses: actions/cache@v4
with:
path: website/public/pet-mad-xs.gguf
key: gguf-pet-mad-xs-${{ hashFiles('website/package.json') }}

- name: Build WASM
run: |
./scripts/build_wasm.sh
Expand All @@ -58,11 +69,11 @@ jobs:

- name: Install website dependencies
working-directory: website
run: npm install
run: bun install --frozen-lockfile

- name: Build website
working-directory: website
run: npm run build
run: bun run build

- name: Setup Pages
uses: actions/configure-pages@v4
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ stdout

# Development directories
testing/

# Local experiments and artifacts (not part of mlipcpp)
local/
petk_codegen/
tinypet/
scripts/repro_ase_optimizer_segfault.py
scripts/stress_ase_optimizer_segfault.py

# WASM build output
wasm/
Expand Down
68 changes: 51 additions & 17 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ option(MLIPCPP_INSTALL "Generate install target" OFF)
option(MLIPCPP_USE_CUDA "Enable CUDA backend via ggml" OFF)
option(MLIPCPP_USE_HIP "Enable HIP/ROCm backend via ggml (AMD)" OFF)
option(MLIPCPP_USE_METAL "Enable Metal backend via ggml" OFF)
option(MLIPCPP_USE_WEBGPU "Enable WebGPU backend via ggml (requires Dawn)" OFF)
option(MLIPCPP_USE_VULKAN "Enable Vulkan backend via ggml" OFF)
option(MLIPCPP_USE_SYCL "Enable SYCL backend via ggml (Intel)" OFF)
option(MLIPCPP_USE_CANN "Enable CANN backend via ggml (Huawei Ascend)" OFF)
option(MLIPCPP_USE_BLAS "Enable BLAS acceleration via ggml" OFF)
option(MLIPCPP_USE_SYSTEM_FMT "Use system-installed fmtlib instead of bundled" OFF)
option(MLIPCPP_WASM_ASYNCIFY "Use ASYNCIFY instead of JSPI for async WebGPU calls in WASM builds" OFF)

# WASM-specific settings
if(EMSCRIPTEN)
Expand All @@ -43,14 +45,15 @@ if(EMSCRIPTEN)
set(MLIPCPP_BUILD_TESTS OFF)
set(MLIPCPP_BUILD_PYTHON OFF)
set(MLIPCPP_BUILD_FORTRAN OFF)
# Disable all GPU backends for WASM
# Disable native GPU backends for WASM (WebGPU is the only option)
set(MLIPCPP_USE_CUDA OFF)
set(MLIPCPP_USE_HIP OFF)
set(MLIPCPP_USE_METAL OFF)
set(MLIPCPP_USE_VULKAN OFF)
set(MLIPCPP_USE_SYCL OFF)
set(MLIPCPP_USE_CANN OFF)
set(MLIPCPP_USE_BLAS OFF)
# MLIPCPP_USE_WEBGPU stays as the user set it (default OFF).
# Tell GGML we're building for WASM so it uses SIMD-optimized kernels
# (Emscripten defaults CMAKE_SYSTEM_PROCESSOR to x86, not wasm)
set(CMAKE_SYSTEM_PROCESSOR "wasm32" CACHE STRING "" FORCE)
Expand Down Expand Up @@ -122,6 +125,17 @@ endif()
if(MLIPCPP_USE_VULKAN)
set(GGML_VULKAN ON CACHE BOOL "" FORCE)
endif()
if(MLIPCPP_USE_WEBGPU)
set(GGML_WEBGPU ON CACHE BOOL "" FORCE)
if(EMSCRIPTEN)
# Default to JSPI; opt in to ASYNCIFY via MLIPCPP_WASM_ASYNCIFY=ON.
if(MLIPCPP_WASM_ASYNCIFY)
set(GGML_WEBGPU_JSPI OFF CACHE BOOL "" FORCE)
else()
set(GGML_WEBGPU_JSPI ON CACHE BOOL "" FORCE)
endif()
endif()
endif()
if(MLIPCPP_USE_SYCL)
set(GGML_SYCL ON CACHE BOOL "" FORCE)
endif()
Expand Down Expand Up @@ -149,7 +163,7 @@ else()
CPMAddPackage(
NAME ggml
GITHUB_REPOSITORY peterspackman/ggml
GIT_TAG 25574148
GIT_TAG 833b864d
EXCLUDE_FROM_ALL YES
)
endif()
Expand All @@ -168,6 +182,16 @@ elseif(NOT EMSCRIPTEN)
)
endif()

# nlohmann_json (for graph inference metadata)
CPMAddPackage(
NAME nlohmann_json
GITHUB_REPOSITORY nlohmann/json
VERSION 3.11.3
OPTIONS
"JSON_BuildTests OFF"
EXCLUDE_FROM_ALL YES
)

# =============================================================================
# Library
# =============================================================================
Expand Down Expand Up @@ -314,24 +338,34 @@ if(EMSCRIPTEN)
target_link_libraries(mlipcpp_wasm PRIVATE mlipcpp)
target_include_directories(mlipcpp_wasm PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)

# Emscripten-specific link flags
set(MLIPCPP_WASM_LINK_FLAGS
"-s WASM=1 "
"-s MODULARIZE=1 "
"-s EXPORT_ES6=1 "
"-s EXPORT_NAME='createMlipcpp' "
"-s ALLOW_MEMORY_GROWTH=1 "
"-s MAXIMUM_MEMORY=4GB "
"-s STACK_SIZE=1MB "
"-s SINGLE_FILE=1 "
"-s EXPORTED_RUNTIME_METHODS=['FS','cwrap','ccall'] "
"-s FORCE_FILESYSTEM=1 "
"--bind "
"-O3 "
)

# When WebGPU is enabled, ggml-webgpu already propagates -sJSPI or
# -sASYNCIFY via INTERFACE link options. Add a larger async stack for
# ASYNCIFY; JSPI doesn't need it.
if(MLIPCPP_USE_WEBGPU AND MLIPCPP_WASM_ASYNCIFY)
list(APPEND MLIPCPP_WASM_LINK_FLAGS "-s ASYNCIFY_STACK_SIZE=65536 ")
endif()

string(REPLACE ";" "" MLIPCPP_WASM_LINK_FLAGS "${MLIPCPP_WASM_LINK_FLAGS}")

set_target_properties(mlipcpp_wasm PROPERTIES
SUFFIX ".js"
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
LINK_FLAGS "\
-s WASM=1 \
-s MODULARIZE=1 \
-s EXPORT_ES6=1 \
-s EXPORT_NAME='createMlipcpp' \
-s ALLOW_MEMORY_GROWTH=1 \
-s MAXIMUM_MEMORY=4GB \
-s STACK_SIZE=1MB \
-s SINGLE_FILE=1 \
-s EXPORTED_RUNTIME_METHODS=['FS','cwrap','ccall'] \
-s FORCE_FILESYSTEM=1 \
--bind \
-O3 \
"
LINK_FLAGS "${MLIPCPP_WASM_LINK_FLAGS}"
)

# Install WASM output
Expand Down
94 changes: 78 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,109 @@

Standalone C++ implementation of Machine Learning Interatomic Potentials (MLIPs) using [ggml](https://github.com/ggml-org/ggml).

Currently supports [PET-MAD](https://github.com/lab-cosmo/pet-mad) for energies, forces, stresses
Currently supports [PET/uPET](https://github.com/lab-cosmo/pet-mad) models (energy, forces, stresses).

## Dependencies
## Quick start (Python)

```bash
# Install the package
pip install .

# Download and convert a model to GGUF
uv run scripts/convert_models.py --models pet-mad-s
```

```python
import numpy as np
import mlipcpp

# Load a model
model = mlipcpp.Predictor("gguf/pet-mad-s.gguf")
print(f"Model type: {model.model_type}, cutoff: {model.cutoff} A")

# Water molecule
positions = np.array([
[0.000, 0.000, 0.000], # O
[0.757, 0.586, 0.000], # H
[-0.757, 0.586, 0.000], # H
], dtype=np.float32)
atomic_numbers = np.array([8, 1, 1], dtype=np.int32)

# Predict energy
result = model.predict(positions, atomic_numbers, compute_forces=False)
print(f"Energy: {result.energy:.4f} eV")
# => Energy: -14.3693 eV

# Predict energy + forces
result = model.predict(positions, atomic_numbers, compute_forces=True)
print(f"Energy: {result.energy:.4f} eV")
forces = np.array(result.forces).reshape(-1, 3)
print(f"Forces (eV/A):\n{forces}")
```

### ASE integration

```python
from ase.io import read
from mlipcpp.ase import MLIPCalculator

atoms = read("structure.xyz")
atoms.calc = MLIPCalculator("gguf/pet-mad-s.gguf")
print(f"Energy: {atoms.get_potential_energy():.4f} eV")
```

## Converting models

Download and convert uPET models from HuggingFace to GGUF format:

```bash
# Convert all available models
uv run scripts/convert_models.py

# Convert a specific model
uv run scripts/convert_models.py --models pet-mad-s

# List available models
uv run scripts/convert_models.py --list
```

Default models: `pet-mad-s`, `pet-oam-l`, `pet-omad-xs`, `pet-omad-s`, `pet-omat-xs`, `pet-omat-s`, `pet-spice-s`

Use `--all` to also convert larger variants: `pet-oam-xl`, `pet-omad-l`, `pet-omat-m`, `pet-omat-l`, `pet-omat-xl`, `pet-omatpes-l`, `pet-spice-l`

## Building from source

### Dependencies

- [ggml](https://github.com/ggml-org/ggml) - Tensor library (fetched automatically via CMake)
- [fmt](https://github.com/fmtlib/fmt) - Formatting library (fetched automatically)

**Note:** This project uses a [modified fork of ggml](https://github.com/peterspackman/ggml) with additional backpropagation support for `CONCAT` and `CLAMP` operations, required for force/stress computation.

## Building
### Build

```bash
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . -j
```

## Converting PET-MAD weights

Download and convert the official PET-MAD model to GGUF format:

```bash
uv run scripts/convert_pet_mad.py --output pet-mad.gguf
```

## Usage
### C++ CLI

```bash
# Energy only
./build/bin/simple_inference pet-mad.gguf structure.xyz
./build/bin/simple_inference gguf/pet-mad-s.gguf structure.xyz

# With forces
./build/bin/simple_inference pet-mad.gguf structure.xyz --forces
./build/bin/simple_inference gguf/pet-mad-s.gguf structure.xyz --forces

# With forces and stress (periodic systems)
./build/bin/simple_inference pet-mad.gguf structure.xyz --forces --stress
./build/bin/simple_inference gguf/pet-mad-s.gguf structure.xyz --forces --stress
```

## API

C, C++, and Fortran APIs are provided. See `examples/` for usage.
C, C++, Fortran, and Python APIs are provided. See `examples/` for usage.

## License

Expand Down
5 changes: 5 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ add_executable(backend_benchmark backend_benchmark.cpp)
target_link_libraries(backend_benchmark PRIVATE mlipcpp ggml fmt::fmt)
target_include_directories(backend_benchmark PRIVATE ${PROJECT_SOURCE_DIR}/src)

# Graph-based inference using auto-exported models
add_executable(graph_inference ${PROJECT_SOURCE_DIR}/src/bin/graph_inference.cpp)
target_link_libraries(graph_inference PRIVATE mlipcpp ggml fmt::fmt nlohmann_json::nlohmann_json)
target_include_directories(graph_inference PRIVATE ${PROJECT_SOURCE_DIR}/src)

# Public API examples (only use public headers)
add_executable(c_api_test c_api_test.c)
target_link_libraries(c_api_test PRIVATE mlipcpp)
Expand Down
Loading
Loading