Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,43 @@
Notable changes of grace-runtime, grace-runtime-cuda12 and grace-runtime-rocm6 (they share one version). Each
release has a section "Changed defaults" when a default behaves differently.

## [0.1.2](https://github.com/ICAMS/grace-runtime/releases/tag/0.1.2) (2026-11-01)

The early GRACE-1L/2L models, and fast GPU kernels for more GRACE-1L/2L fits.

### Added

- **Early GRACE-1L/2L models:** GRACE-1L-OAM, GRACE-1L-OMAT, GRACE-2L-OAM and GRACE-2L-OMAT (and their older aliases)
are in the registry and run on the CPU, NVIDIA and AMD GPUs, in Python and in LAMMPS, without an uncertainty head.
Own fits of the early GRACE-1L/2L presets run as well: tensorpotential exports them as `kokkos.npz` format 2.
- **More GRACE-1L/2L fits on the fast GPU kernels.** A fit whose layers are narrower than compiled GPU kernels runs
zero-padded to them, with the same results and a warning that names the widths (not models with an uncertainty
head). GRACE-2L has kernels for the widths of the current registry models, of the early ones, and of fits with 48
layer-2 radial channels; GRACE-1L fits run with up to 64 radial channels. The models guide lists the widths.
- `GRACE_GENERIC_KERNELS=1`: a GRACE-2L fit wider than all compiled GPU kernels runs on generic GPU kernels, several
times slower, with a warning. Without the variable such a fit stops with an error that names its widths.

### LAMMPS (`grace-runtime` branch of the LAMMPS fork)

- `grace/runtime` and `grace/runtime/kk` run the early GRACE-1L/2L models and own fits of their presets. The Kokkos
style pads narrower fits like Python does, and with `GRACE_GENERIC_KERNELS=1` runs wider GRACE-2L fits on the
generic GPU kernels. Warnings appear as LAMMPS `WARNING` lines.

### Documentation

- Benchmarks: H200, MI250X, L40S and CPU charts; the front page shows the execution speed.
- Models: which fits run on the fast GPU kernels, padded or not, and `GRACE_GENERIC_KERNELS`.

### Changed defaults

- A GRACE-1L/2L model without GPU kernels of its own widths stopped with an error on a GPU. A narrower one now runs
zero-padded with a warning; a wider GRACE-2L one still stops, and the error names `GRACE_GENERIC_KERNELS=1`.
- `device="auto"`: such a wider GRACE-2L model raises instead of running on the CPU.
- `kokkos.npz` format version 2 for the early GRACE-1L/2L layouts. grace-runtime 0.1.1 and older refuse these files
and ask for an update. Files of current models stay format 1.
- The GPU modules of `grace-runtime-cuda12` / `grace-runtime-rocm6` 0.1.2 have interface version 7; grace-runtime
0.1.2 refuses older modules. The packages pin each other, so a normal `pip install` matches them.

## [0.1.1](https://github.com/ICAMS/grace-runtime/releases/tag/0.1.1) (2026-10-29)

Bug fixes and documentation.
Expand Down
6 changes: 3 additions & 3 deletions docs/lammps.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ cd lammps
## 2. Build

The pair styles are part of the `ML-PACE` package. When CMake configures the build, it downloads grace-runtime
0.1.1 from GitHub, so the configure step needs network access. It also downloads the ML-PACE library. Pick one of the
0.1.2 from GitHub, so the configure step needs network access. It also downloads the ML-PACE library. Pick one of the
three recipes; run each from the `lammps` folder.

### CPU
Expand Down Expand Up @@ -131,10 +131,10 @@ Other AMD GPUs ([GPU backends](backends.md#amd-rocm)):

### Without network access

Download grace-runtime 0.1.1 on a machine with network access, copy it over and pass its path:
Download grace-runtime 0.1.2 on a machine with network access, copy it over and pass its path:

```bash
git clone --depth 1 -b 0.1.1 https://github.com/ICAMS/grace-runtime.git
git clone --depth 1 -b 0.1.2 https://github.com/ICAMS/grace-runtime.git
cmake -S cmake -B build-cpu ... -D LOCAL_GRACE_RUNTIME=$PWD/grace-runtime
```

Expand Down
19 changes: 16 additions & 3 deletions docs/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,29 @@ grace-runtime models download GRACE-2L-OMAT-medium-ft-E
```

OMAT models use a 6 Å cutoff; SMAX variants use element-dependent cutoffs of 5–7.5 Å.
Older registry aliases are accepted. Legacy GRACE-FS and early OAM/OMAT models without a Kokkos export require
tensorpotential's `TPCalculator` instead. PACE (ACE) models fitted with pacemaker run from their `.yaml`: see
[PACE models](pace.md).
Older registry aliases are accepted. The early models GRACE-1L-OAM, GRACE-1L-OMAT, GRACE-2L-OAM and GRACE-2L-OMAT
run as well, without an uncertainty head. Legacy GRACE-FS models require tensorpotential's `TPCalculator`. PACE (ACE) models fitted
with pacemaker run from their `.yaml`: see [PACE models](pace.md).

To use your own model, export it with tensorpotential and pass the resulting file:

```bash
grace_utils -p model.yaml -c CHECKPOINT export_kokkos -o model.npz
```

Fits of the early GRACE-1L/2L presets export the same way. Their files are format 2; an older grace-runtime refuses
them and asks for an update.

On a GPU, GRACE-2L fits up to the widths of the registry models run on the fast kernels, narrower layers zero-padded
with the same results and a warning (lmax at most 4; not models with an uncertainty head): a fit of the current presets
with at most 42 layer-1 and 32 layer-2 radial channels, 64 layer-2 product functions and `n_mlp_dens` at most 16, and
any fit with at most 32 layer-1 and 48 layer-2 radial channels, 48 layer-2 product functions and `n_mlp_dens` at most
12. GRACE-1L fits with up to 64 radial channels and FC outputs run zero-padded the same way. Wider GRACE-2L fits stop
with an error that names their widths, also with `device="auto"`; with `GRACE_GENERIC_KERNELS=1` set in the environment
they run on generic GPU kernels, several times slower, with a warning. Please open an
[issue](https://github.com/ICAMS/grace-runtime/issues) with the widths the message names so that fast kernels can be
added.

After exporting `model.npz`, load it with:

```python
Expand Down
2 changes: 2 additions & 0 deletions libgrace/include/grace/fused_1l.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class Grace1LFused {
std::vector<double> e_norm;
std::vector<int> e_nin, e_nout;
int e_act = 0;
bool e_ln = false; // legacy models: RMS layer norm of the MLP input (ln_fwd)
bool aaa_a = false; // legacy models: AAA = AA1 x A (else AA1 x A1)
double out_scale = 1.0;

std::vector<int> order, bstart, bcount;
Expand Down
3 changes: 3 additions & 0 deletions libgrace/include/grace/fused_2l.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,13 @@ class Grace2LFused {

// RMSNorms + energy MLP (double)
std::vector<double> lnI_scale, ln0_scale;
bool rms = true; // the RMSNorms (off: legacy models, unit scales)
int nrms1 = 0, nrms0 = 0; // the RMS means of rho[1:] / I2 divide by these (padded model: the unpadded widths)
std::vector<std::vector<double>> eW;
std::vector<double> e_norm;
std::vector<int> e_nin, e_nout;
int e_act = 1;
bool e_ln = false; // legacy models: RMS layer norm of the MLP input (ln_fwd)
double out_scale = 1.0;

// per-atom globals
Expand Down
70 changes: 19 additions & 51 deletions libgrace/include/grace/fused_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,57 +243,6 @@ inline float dot3(const float *__restrict x, const float *__restrict y, const fl

inline void vzero(float *y, const size_t n) { std::memset(y, 0, n * sizeof(float)); }

// fp64: Chebyshev T_1..T_nrb of (2x-1) times fcut_p(x), and d/dx
inline void radial_basis_x(double x, int p, int nrb, std::vector<double> &g, std::vector<double> &dg)
{
const double xp = std::pow(x, p), xp1 = xp * x, xp2 = xp1 * x;
const double fc = 1.0 - 0.5 * (p + 1) * (p + 2) * xp + p * (p + 2) * xp1 - 0.5 * p * (p + 1) * xp2;
const double dfc = 0.5 * p * (p + 1) * (p + 2) * (-std::pow(x, p - 1) + 2.0 * xp - xp1);
const double t = 2.0 * x - 1.0;
double Tp = 1.0, Tc = t, dTp = 0.0, dTc = 2.0;
g.resize(nrb);
dg.resize(nrb);
for (int k = 0; k < nrb; k++) {
g[k] = Tc * fc;
dg[k] = dTc * fc + Tc * dfc;
const double Tn = 2.0 * t * Tc - Tp, dTn = 2.0 * (2.0 * Tc + t * dTc) - dTp;
Tp = Tc; dTp = dTc; Tc = Tn; dTc = dTn;
}
}

// fp64 forward-mode radial MLP (silu hidden layers, linear output)
template<class Layers>
void mlp_x(const Layers &layers, std::vector<double> h, std::vector<double> dh,
std::vector<double> &out, std::vector<double> &dout)
{
const int n = layers.size();
for (int il = 0; il < n; il++) {
const auto &L = layers[il];
std::vector<double> s(L.n_out, 0.0), ds(L.n_out, 0.0);
for (int k = 0; k < L.n_in; k++)
for (int j = 0; j < L.n_out; j++) {
const double w = L.W[(size_t) k * L.n_out + j];
s[j] += w * h[k];
ds[j] += w * dh[k];
}
for (int j = 0; j < L.n_out; j++) {
s[j] *= L.norm;
ds[j] *= L.norm;
if (il < n - 1) {
const double sg = 1.0 / (1.0 + std::exp(-s[j]));
ds[j] = sg * (1.0 + s[j] * (1.0 - sg)) * ds[j];
s[j] = s[j] * sg;
}
}
h.swap(s);
dh.swap(ds);
}
out.swap(h);
dout.swap(dh);
}



// 16-float vectors (one AVX-512 register, two halves on AVX2: grace_cpu_simd.h). Unaligned access.
typedef simd::f16 v16;
inline v16 ld(const float *p) { return simd::load(p); }
Expand Down Expand Up @@ -712,6 +661,25 @@ inline void red_bwd(const Red &R, int ty, const float *gOut, float *const *gX)
default: break; \
}

// legacy GRACE-1L/2L: the RMS layer norm z = x q of the energy-MLP input x[0..n) in place (its scale folded into the
// first layer), q = 1 / sqrt(mean x^2 + 1e-16) as tensorpotential's scalar_rms_ln; x0 keeps the input. Returns q.
inline double ln_fwd(double *x, double *x0, int n)
{
double ms = 0.0;
for (int k = 0; k < n; k++) ms += (x0[k] = x[k]) * x[k];
const double q = 1.0 / std::sqrt(ms / n + 1e-16);
for (int k = 0; k < n; k++) x[k] *= q;
return q;
}

// its reverse in place: g = dE/dz -> dE/dx
inline void ln_bwd(double *g, const double *x0, int n, double q)
{
double t = 0.0;
for (int k = 0; k < n; k++) t += g[k] * x0[k];
for (int k = 0; k < n; k++) g[k] = q * (g[k] - x0[k] * t * q * q / n);
}

// ---- bond geometry: neighbours within the cutoff, unit vectors, real spherical harmonics Y[lm] and the
// gradient G[lm][3] of their polynomial extension (dual numbers). Shared by the CPU GRACE-1L and 2L drivers.

Expand Down
49 changes: 5 additions & 44 deletions libgrace/include/grace/kk/fused_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ namespace grace {
namespace kk {
namespace GraceFusedKK {

// the last sentence of the warnings for a model without GPU kernels of its own widths
constexpr const char *GRACE_KK_ISSUE =
"Please open an issue at https://github.com/ICAMS/grace-runtime/issues with these numbers so that fast kernels "
"can be added";

constexpr int GRACE_FUSED_MAX_LMAX = 4;

struct alignas(16) GF4 { float x, y, z, w; };
Expand Down Expand Up @@ -185,50 +190,6 @@ void spline_vd(const View3 &c, const int N, const float x, const int o, float &v
dv = (a1 + t * (2.0f * a2 + t * 3.0f * a3)) * (float) N;
}

// Host fp64: Chebyshev T_1..T_nrb of (2x-1) times fcut_p(x), and d/dx (x = r / rcut_ij).
inline void radial_basis_x(double x, int p, int nrb, std::vector<double> &g, std::vector<double> &dg)
{
const double xp = std::pow(x, p), xp1 = xp * x, xp2 = xp1 * x;
const double fc = 1.0 - 0.5 * (p + 1) * (p + 2) * xp + p * (p + 2) * xp1 - 0.5 * p * (p + 1) * xp2;
const double dfc = 0.5 * p * (p + 1) * (p + 2) * (-std::pow(x, p - 1) + 2.0 * xp - xp1);
const double t = 2.0 * x - 1.0;
double Tp = 1.0, Tc = t, dTp = 0.0, dTc = 2.0; // d/dx, chain factor 2
g.resize(nrb); dg.resize(nrb);
for (int k = 0; k < nrb; k++) {
g[k] = Tc * fc;
dg[k] = dTc * fc + Tc * dfc;
const double Tn = 2.0 * t * Tc - Tp, dTn = 2.0 * (2.0 * Tc + t * dTc) - dTp;
Tp = Tc; dTp = dTc; Tc = Tn; dTc = dTn;
}
}

// Host fp64 forward-mode radial MLP (silu hidden layers, linear output), as TagComputeMLPRadial_R.
template<class Layer>
void mlp_x(const std::vector<Layer> &layers, std::vector<double> h,
std::vector<double> dh, std::vector<double> &out, std::vector<double> &dout)
{
const int n = layers.size();
for (int il = 0; il < n; il++) {
const auto &L = layers[il];
std::vector<double> s(L.n_out, 0.0), ds(L.n_out, 0.0);
for (int k = 0; k < L.n_in; k++)
for (int j = 0; j < L.n_out; j++) {
const double w = L.W[(size_t) k * L.n_out + j];
s[j] += w * h[k]; ds[j] += w * dh[k];
}
for (int j = 0; j < L.n_out; j++) {
s[j] *= L.norm; ds[j] *= L.norm;
if (il < n - 1) {
const double sg = 1.0 / (1.0 + std::exp(-s[j]));
ds[j] = sg * (1.0 + s[j] * (1.0 - sg)) * ds[j];
s[j] = s[j] * sg;
}
}
h.swap(s); dh.swap(ds);
}
out.swap(h); dout.swap(dh);
}

} // namespace GraceFusedKK
} // namespace kk
} // namespace grace
Expand Down
9 changes: 9 additions & 0 deletions libgrace/include/grace/kk/grace_1l_fused_kk.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ class Grace1LFusedKK : public Grace1LKK<DeviceType, float, float, Traits> {

// checks the model against the compiled kernels, builds the dense metadata and the radial tables
void setup() override;
// a model without UQ whose radial or FC width has no compiled kernels runs zero-padded (GRACE1LModel::padded: the
// same results), with a warning
void set_model(std::shared_ptr<GRACE1LModel> model, const std::vector<int> &type2mu) override;
// the widths {radial channels, FC outputs} set_model pads a model to; {0, 0}: none
static std::array<int, 2> pad_widths(const GRACE1LModel &m);
// the model zero-padded to its pad_widths; the model itself without them
static std::shared_ptr<GRACE1LModel> padded_model(std::shared_ptr<GRACE1LModel> model);
// the warning for a model that runs zero-padded; empty otherwise
static std::string slow_notice(const GRACE1LModel &m);
typename Base::RunOutput run(const typename Base::RunInput &in) override;
void release_buffers() override
{
Expand Down
Loading
Loading