TopG / API.md
RGPalgrave's picture
add API brief
51dd783 verified
|
Raw
History Blame Contribute Delete
8.08 kB
# TopG API — brief for another agent
Everything needed to call the TopG structure generator. Self-contained: paste this whole file.
## What it does
TopG takes a **coordination query** — a description of each inequivalent metal site's local
environment — and returns **complete crystal structures**: space group, Wyckoff positions, free
coordinates and cell shape. It is a 4.5M-parameter conditional transformer. **No search or
refinement is involved; the output is the model's raw emission.**
It generates a **metal sublattice**, not a composition. Element identities in the returned CIF are
arbitrary palette entries and carry no chemical meaning.
## Endpoint and auth
- Space `RGPalgrave/TopG-demo` · base URL `https://rgpalgrave-topg-demo.hf.space`
- Endpoint **`/generate`** — use this one. (`/run` is the web page's own button and takes
UI-shaped arguments.)
- **The Space is private, so every call needs a HuggingFace token** with read access to it.
Pass it via the `HF_TOKEN` environment variable; do not hard-code it.
## Python
```python
import json, os
from gradio_client import Client # pip install gradio_client
c = Client("RGPalgrave/TopG-demo", token=os.environ["HF_TOKEN"])
r = c.predict(json.dumps({
"sites": [
{"H": "4/mmm", "cs": [4, 2], "ratios": [1.0, 1.15], "orbit_size": 2},
{"H": "mmm", "cs": [2, 4], "ratios": [1.0, 1.02], "orbit_size": 2}
],
"n_atoms": 4, "model": "H_pq0", "candidates": 8, "seed": 0,
"score": True, "cif": True
}), api_name="/generate")
r = json.loads(r) if isinstance(r, str) else r
```
## curl
POST returns an `event_id`; GET streams the result.
```bash
EV=$(curl -s -X POST "https://rgpalgrave-topg-demo.hf.space/gradio_api/call/generate" \
-H "Authorization: Bearer $HF_TOKEN" -H "Content-Type: application/json" \
-d '{"data":["{\"sites\":[{\"H\":\"m-3m\",\"cs\":[6,12],\"ratios\":[1.0,1.414],\"orbit_size\":4}],\"n_atoms\":4}"]}' \
| python -c "import sys,json;print(json.load(sys.stdin)['event_id'])")
curl -s -N "https://rgpalgrave-topg-demo.hf.space/gradio_api/call/generate/$EV" \
-H "Authorization: Bearer $HF_TOKEN" | grep -m1 '^data:'
```
## Request fields
| field | required | meaning |
|---|---|---|
| `sites` | **yes** | one object per *inequivalent* site (below). 1–12 of them |
| `n_atoms` | no | metal atoms in the **conventional** cell, 1–192. Defaults to the sum of `orbit_size`. **Orbit sizes must sum to it** — a mismatch is accepted but returns a `warning` and usually few or no structures |
| `model` | no | `H_pq0` (default), `H_pq1`, `H_pq2`, `I_full0`, `I_full1`, `I_full2` |
| `candidates` | no | beams to draw, default 8. More candidates → more distinct structures, linear cost |
| `seed` | no | default 0 |
| `score` | no | default `true`; scores each structure against the query. The slow part for large cells. `false` returns `best_rung: null` |
| `cif` | no | default `true`; `false` omits CIF text |
Each entry of `sites`:
| field | meaning |
|---|---|
| `H` | site symmetry, Hermann–Mauguin (table below) |
| `cs` | coordination sequence — metal neighbours in each successive shell, e.g. `[4, 2]` |
| `ratios` | each shell's distance **relative to the nearest**, so `ratios[0]` is always `1.0` |
| `orbit_size` | atoms this site contributes to the conventional cell |
`cs` and `ratios` must be the same length: **1 to 6 shells**. Fewer than 6 is a *partial query*
supported, and easier for the model — but **use an `H_pq` model for it**. `I_full` is trained on
full-depth queries only and collapses on short ones (~10% vs ~50% skeleton accuracy).
## Accepted site symmetries (36)
Any symmetry may be used in any query; the row says where it actually occurs among the 230 space groups.
| system | site symmetries |
|---|---|
| triclinic | `1` `-1` |
| monoclinic | `1` `-1` `2` `m` `2/m` |
| orthorhombic | `1` `-1` `2` `m` `2/m` `222` `2mm` `m2m` `mm2` `mmm` |
| tetragonal | `1` `-1` `2` `m` `-4` `2/m` `222` `2mm` `4` `m2m` `-42m` `-4m2` `4/m` `422` `4mm` `mmm` `4/mmm` |
| trigonal | `1` `-1` `2` `m` `3` `2/m` `-3` `32` `3m` `-3m` |
| hexagonal | `1` `-1` `2` `m` `3` `2/m` `222` `2mm` `m2m` `mm2` `-3` `-6` `32` `3m` `6` `mmm` `-3m` `-62m` `-6m2` `6/m` `622` `6mm` `6/mmm` |
| cubic | `1` `2` `m` `3` `-4` `2/m` `222` `2mm` `4` `mm2` `-3` `32` `3m` `-42m` `-4m2` `4/m` `422` `4mm` `mmm` `-3m` `23` `4/mmm` `-43m` `432` `m-3` `m-3m` |
**Not usable:** `312` `31m` `321` `3m1` `-31m` `-3m1` — these are in the model's vocabulary but occur in no Wyckoff table, so no
training example ever contained one. The API rejects them; use the form without the axis suffix
(`321``32`, `3m1``3m`, `-3m1``-3m`).
## Response
```json
{"ok": true,
"query": {"n_atoms": 4, "k": 2, "depth": 2, "sites": [...]},
"candidates_built": 8, "distinct_structures": 2, "warning": null,
"provenance": {"model": "H_pq0", "tokenizer_fingerprint": "e1db473d06e14c82",
"device": "cpu", "note": "pure model output; no search or refinement"},
"structures": [
{"rank": 1, "space_group": 139, "crystal_system": "tetragonal",
"orbits": "2a 2b", "cell_shape": "c_over_a=1.4714",
"best_rung": "r0_2sh_noratio", "times_drawn": 6, "cif": "# generated using pymatgen..."}
]}
```
Errors never raise — they return `{"ok": false, "error": "..."}`, with `expected` carrying the
schema when the payload was malformed.
- `structures` are **deduplicated** and ranked: scored hits first, then by `times_drawn`.
- `times_drawn` is how many of the `candidates` beams produced that same structure — a rough
confidence signal, not a probability.
- `cell_shape` lists only the **free** shape parameters of the crystal system (cubic none;
tetragonal/trigonal/hexagonal `c_over_a`; orthorhombic 2, monoclinic 3, triclinic 5).
**No absolute length is emitted** — a scale-free query cannot determine one, so the CIF's absolute
cell size is a placeholder and only ratios are meaningful.
- The **CIF is written in P1** with every atom explicit, so the file says `P 1` while `space_group`
gives the real symmetry. The symmetry is in the coordinates.
## `best_rung` — how well a structure answers the query
Nested criteria, each stricter than the last. `null` means it passed none.
| rung | shells checked | distance tolerance |
|---|---|---|
| `r0_2sh_noratio` | 2 | ignored |
| `r1_3sh_noratio` | 3 | ignored |
| `r2_3sh_t04` | 3 | 4% |
| `r2a_3sh_t08` | 3 | 8% |
| `r5_6sh_noratio` | 6 | ignored |
| **`r3_6sh_t04`** | **6** | **4%** — the project's historical criterion |
| `r3a_6sh_t08` | 6 | 8% |
| `r3b_6sh_t15` | 6 | 15% |
## How much to trust the output
Measured on a frozen, skeleton-disjoint evaluation set; pure model, no search:
- The **discrete** answer (space group + Wyckoff labels + N) is exactly right **~54–59%** of the time.
- The **geometry** meets the strict `r3_6sh_t04` criterion **~2–3%** of the time, and essentially
never above ~9 free parameters. **Treat returned coordinates as a starting point, not an answer.**
- A *perfect* model would score **95.67%**, not 100% — that is the emission grid's own ceiling.
- A structure passing no rung still answers the query approximately; `best_rung` says which
criterion it actually meets.
## Gotchas
- **`seed` reproduces within one deployment, not across environments.** The same seed on this Space
and on a local checkout gives the same structures but different draw counts, because the Python
and torch builds differ. Do not use `seed` as a portable identifier.
- **The first call after the Space wakes is slow** — it downloads the checkpoint once, then caches.
A small query (N ≤ 8, 8 candidates) then takes a few seconds.
- Cost grows with **cell size**, not with hardware; the model is too small for a GPU to help.
For N > 40 send `"score": false`.
- Sites are **inequivalent sites, not atoms**: `k` is the number of orbits, `n_atoms` the number of
atoms, and `orbit_size` links them.
Model card: `RGPalgrave/TopG` · code and full record: <https://github.com/rgpalgrave/TopG>