Skip to content

Commit 9a90b05

Browse files
Zikkyingcursoragent
andcommitted
Harden apex-flow skill for batch jobs, RSS, and VASP POTCAR uploads.
Add multi-structure config generation, disable non-TTY RSS tqdm by default, stage VASP POTCARs into job-relative paths, and tighten agent guidance for structure size and crystallographic planes. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 0cb370f commit 9a90b05

11 files changed

Lines changed: 728 additions & 88 deletions

File tree

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,12 +638,32 @@ Property selection behavior:
638638
639639
### 4.5 Decohesive energy line
640640
641+
Decohesive builds a rigid-separation series on one user-specified Miller plane via pymatgen `SlabGenerator`. It does **not** auto-enumerate planes (unlike `surface`) and has **no** crystal-type nested overrides (unlike `gamma`). Any structure that can form that slab is supported; set `miller_index` explicitly.
642+
643+
Recommended default planes by crystal family (JSON `miller_index` uses **3-index** Miller notation):
644+
645+
| Crystal structure | Recommended planes | JSON `miller_index` examples |
646+
|-------------------|--------------------|------------------------------|
647+
| **FCC** | $(100)$, $(110)$, $(111)$ | `[1,0,0]`, `[1,1,0]`, `[1,1,1]` |
648+
| **BCC** | $(100)$, $(110)$, $(111)$ | `[1,0,0]`, `[1,1,0]`, `[1,1,1]` |
649+
| **Diamond** | $(100)$, $(110)$, $(111)$ | `[1,0,0]`, `[1,1,0]`, `[1,1,1]` |
650+
| **Zinc blende** | $(100)$, $(110)$, $(111)$ | `[1,0,0]`, `[1,1,0]`, `[1,1,1]` |
651+
| **Rocksalt** | $(100)$, $(110)$, $(111)$ | `[1,0,0]`, `[1,1,0]`, `[1,1,1]` |
652+
| **HCP** | $(0001)$, $(10\bar{1}0)$, $(11\bar{2}0)$ | `[0,0,1]`, `[1,0,0]`, `[1,1,0]` |
653+
| **Perovskite** | $(001)$, $(110)$, $(111)$ | `[0,0,1]`, `[1,1,0]`, `[1,1,1]` |
654+
655+
Notes:
656+
657+
- HCP must use the **3-index** values above. Four-index Miller–Bravais vectors (e.g. `[0,0,0,1]`) are **not** accepted by `decohesive` (no Bravais conversion).
658+
- Polar / multi-termination faces (common for zinc blende $(111)$ and some perovskite cuts) still generate; APEX takes the first matching slab termination from pymatgen.
659+
- If the user does not specify a plane, prefer a low-index face from the table for the detected lattice and confirm before submit.
660+
641661
| Key | Type | Example | Description |
642662
|-----|------|---------|-------------|
643663
| `min_slab_size` | Integer | `10` | Minimum slab thickness. |
644664
| `max_vacuum_size` | Integer | `11` | Maximum vacuum width. |
645665
| `pert_xz` | Float | `0.01` | Perturbation along xz plane for surface energy. |
646-
| `miller_miller` | List[Int] | `[1, 1, 0]` | Miller indices of the target plane. |
666+
| `miller_index` | List[Int] | `[1, 1, 0]` | Miller indices of the target plane (**required**, 3-index). |
647667
648668
### 4.6 Elastic
649669

apex/rss.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import sys
23
from pathlib import Path
34

45
from pymatgen.core import Structure
@@ -18,6 +19,21 @@
1819
from apex.core.lib.rss import generate_rss, resolve_parent_lattice_auto
1920

2021

22+
def _resolve_show_progress(config: dict, stdout=None) -> bool:
23+
"""Resolve RSS progress-bar flag.
24+
25+
Explicit ``show_progress`` in rss.json always wins. Otherwise enable tqdm
26+
only on an interactive TTY so agent/CI captured runs do not flood logs.
27+
"""
28+
if "show_progress" in config:
29+
return bool(config["show_progress"])
30+
stream = sys.stdout if stdout is None else stdout
31+
try:
32+
return bool(stream.isatty())
33+
except Exception:
34+
return False
35+
36+
2137
def _jsonable(value):
2238
if isinstance(value, dict):
2339
result = {}
@@ -235,7 +251,7 @@ def run_rss_config(config_file: str) -> None:
235251
"allow_vacancies": config.get("allow_vacancies", False),
236252
"num_configs": config.get("num_configs", 1),
237253
"interval": config.get("interval", 100),
238-
"show_progress": config.get("show_progress", True),
254+
"show_progress": _resolve_show_progress(config),
239255
"patience": config.get("patience"),
240256
"return_metadata": write_metadata,
241257
}

apex/skills/apex-flow/SKILL.md

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,17 @@ Options to offer via AskQuestion:
7373
(e.g. “用 EAM”, “用 ABACUS 做 EOS”, “用 DPA-3.2-5M-OMat24.pth”).
7474
**If AskQuestion times out or fails**: state the intended APEX backend and bundled model selection (if LAMMPS+DPA) in plain text and WAIT. Never silently submit.
7575
2. **STOP: Confirm property parameters before submission — DO NOT PROCEED WITHOUT USER ANSWER.** Before submitting, present the full `properties` configuration (JSON) to the user. Show the defaults that will be used and highlight:
76-
- Miller indices (for surface/gamma/decohesive)
76+
- Miller indices / slip systems (for surface/gamma/gamma_surface/decohesive)
7777
- Supercell sizes (for vacancy/interstitial/phonon/gruneisen/finite-T)
7878
- Temperature ranges (for finite_t_latt/finite_t_elastic/annealing)
7979
- Number of deformation/step points
80+
For crystallographic planes:
81+
- `gamma` / `gamma_surface`: pick from the canonical FCC/BCC/HCP table in
82+
repository **README §4.10** (see also `reference/properties.md` §8–9). Do not
83+
invent slip systems; do not silently change an approved plane/direction.
84+
- `decohesive`: pick `miller_index` from the crystal-family table in
85+
**README §4.5** / `reference/properties.md` §10 (FCC/BCC/Diamond/ZB/Rocksalt/
86+
HCP/Perovskite). HCP must use **3-index** only.
8087
Let the user approve or modify. **Skip ONLY if** the user provided explicit property parameters already.
8188
**If AskQuestion times out or fails**: display the parameters in your message and WAIT for confirmation before submitting.
8289
3. **Two-layer architecture.** The outer Bohrium job is a thin submission client only. Never attempt `apex do` for production workflows — use `apex submit` which delegates to dflow. See `reference/submission.md` for the full architecture diagram.
@@ -97,6 +104,7 @@ Options to offer via AskQuestion:
97104
4. **Kill = inner FIRST, outer SECOND.** If you only kill the outer Bohrium node, the dflow workflow continues consuming resources silently. Always terminate the inner dflow workflow first. See `reference/workflow-control.md`.
98105
5. **MUST use `generate_config.py`; never hand-write `param.json` or `global.json`.**
99106
- Create the complete job with `python <skill-root>/scripts/generate_config.py create ...`.
107+
- For multiple structures, pass repeated/space-separated `--structure` and/or `--structure-dir` to `create` (it copies each into `confs/<name>/` and fills `structures`); do not hand-edit `structures` after create.
100108
- To preserve an approved `param.json` while refreshing credentials, run
101109
`python <skill-root>/scripts/generate_config.py refresh-global --global global.json`
102110
from the task directory. This updates only `global.json`.
@@ -136,19 +144,42 @@ Options to offer via AskQuestion:
136144
(`scripts/fetch_models.py --source-checkpoint` or
137145
`dp --pt pretrained download DPA-3.2-5M`) and freeze that head before use.
138146
See `models/README.md`.
139-
11. **Preserve the user's input cell and prevent accidental double expansion.**
147+
11. **STOP: Check atom count / cell size before property submit — decide whether to expand.**
140148
APEX does not require a conventional cell. Do not convert a primitive cell or
141149
user-provided supercell to a conventional cell merely because an example uses
142150
`confs/std-fcc` or another `std-*` name.
143-
- Inspect the supplied structure and determine whether it is already a supercell.
144-
- If it is a supercell, ask whether the user wants any additional replication.
145-
- If the answer is no, explicitly set applicable volumetric `supercell` or
146-
`supercell_size` parameters to `[1, 1, 1]` so APEX does not expand it again.
151+
Before confirming property parameters, **always read the user's structure** and
152+
report: formula, atom count, lattice lengths, and whether it looks like a
153+
primitive / conventional / already-expanded supercell.
154+
Then decide with the user whether further bulk expansion is needed:
155+
- **Too small for the property** (typical primitive or tiny conventional cell)
156+
→ recommend expanding; do not silently submit with an undersized cell.
157+
- **Already large enough / already a supercell** → ask whether to expand again;
158+
if no, set applicable volumetric `supercell` / `supercell_size` to `[1,1,1]`
159+
so APEX does not expand twice.
147160
- Keep `elastic.conventional` false unless the user explicitly requests a
148-
conventional-cell elastic calculation.
149-
- Slab construction parameters for surface/gamma/decohesive calculations are
150-
property geometry controls; confirm them separately rather than treating them
151-
as generic bulk expansion.
161+
conventional-cell elastic calculation.
162+
- Slab properties (`surface` / `gamma` / `decohesive`) use `min_slab_size` /
163+
in-plane replication, not bulk `supercell`; confirm those separately.
164+
Use the helper wording and size guidance in
165+
`reference/workflow-control.md`**Pre-Submission Structure Validation**.
166+
12. **STOP: When the user gives a VASP POTCAR path, verify it and stage it into the job.**
167+
Host libraries such as `/share/PAW_PBE/...` are **not** available inside
168+
Bohrium/dflow containers. Leaving an absolute `potcar_prefix` in `param.json`
169+
causes `FileNotFoundError: .../Ti_pv/POTCAR` after upload.
170+
As soon as the user specifies a POTCAR library path:
171+
1. Confirm the path exists and is readable locally.
172+
2. Confirm every structure element has a POTCAR file under that library
173+
(potpaw: prefer `"Ti": "Ti_pv/POTCAR"`).
174+
3. Create the job with `generate_config.py create ... --potcar-prefix <lib>
175+
--potcars 'Ti:Ti_pv/POTCAR,...'` — the script **copies** needed files into
176+
`vasp_potcar/` and rewrites `potcar_prefix` to the relative `vasp_potcar`.
177+
4. Verify `param.json` uses `"potcar_prefix": "vasp_potcar"` (not `/share/...`)
178+
and that `vasp_potcar/<entry>` exists in the uploaded directory; then run
179+
`validate_inputs.py`.
180+
If the library is missing/incomplete: **STOP**, tell the user the path is
181+
unusable, and ask for the correct POTCAR location. Never submit with an
182+
absolute host POTCAR path hoping the container can see it.
152183

153184

154185

@@ -230,7 +261,15 @@ See `reference/submission.md` for the full validated template.
230261
2. **Model files must be in job directory.** For MLIP workflows, the model file (`.pb`, `.pth`, `.model`, etc.) must be present in the submitted directory. Use relative paths in `param.json`. For DeePMD/DPA, copy `models/DPA-3.2-5M/DPA-3.2-5M-OMat24.pth`. Default to `"type_map": "auto"` for every LAMMPS interaction; specify a dictionary only when the user explicitly needs a fixed custom ordering.
231262
3. **Joint workflow recommended.** Use `joint` flow (relaxation + properties) for most use cases to ensure proper relaxation before property calculations.
232263
4. **GPU for ML potentials.** DeePMD, MACE, and NEP benefit from GPU acceleration. Set `scass_type` to a validated GPU SKU from `validate_apex_combo.py recommend --prefer gpu` (default: `"c8_m31_1 * NVIDIA T4"`).
233-
5. **Supercell sizing applies to unit-cell inputs only.** For defect calculations (vacancy, interstitial), a total cell equivalent to at least a [2,2,2] unit-cell expansion is normally needed. For phonon, [3,3,3] total size is recommended (phonoLAMMPS may fail with a smaller total cell). If the input is already a supercell and the user declines further expansion, use `[1,1,1]`; do not apply these factors again.
264+
5. **Supercell sizing depends on the input atom count, not only the default JSON.**
265+
Treat defaults as targets for **unit-cell inputs**. First inspect the user's
266+
structure; if it is already large enough, prefer `[1,1,1]` after confirmation.
267+
Rough total-size guidance (after any expansion):
268+
- vacancy / interstitial: ≳ [2,2,2] conventional-cell equivalent
269+
- phonon / gruneisen / finite-T: ≳ [3,3,3] (smaller cells often fail)
270+
- surface / gamma / decohesive: ensure slab thickness / in-plane size, not bulk supercell
271+
If the cell is too small, ask the user to expand before submit. See
272+
`reference/workflow-control.md`.
234273
6. **Outer job machine.** Use `c1_m2_cpu` for the outer Bohrium job since it only calls `apex submit` and waits. Don't waste larger CPU or GPU resources on the submission client.
235274

236275

@@ -243,6 +282,18 @@ structures before property calculations. Read `reference/rss_workflow.md`
243282
before asking the user questions or writing `rss.json`; it defines the required
244283
QA, current JSON schema, output layout, and visualization fallback.
245284

285+
**Agent rules for RSS (mandatory):**
286+
- Always set `"show_progress": false` in `rss.json`. tqdm step bars (default
287+
`max_steps=20000`) flood captured terminal output and waste context; do not
288+
leave progress enabled “to see if it is working.”
289+
- After `apex rss`, judge success from files + metadata — not from live bars:
290+
count `conf_*/POSCAR`, then read `rss_metadata.json` for convergence /
291+
composition / duplicate warnings.
292+
- If zero configs are written, do **not** re-call `generate_rss` from Python to
293+
bypass the CLI. Fix `rss.json` (`max_steps`, `interval`, `num_configs`,
294+
compositions, cell size) and re-run `apex rss` once; report the metadata
295+
diagnosis to the user.
296+
246297
## Working Test Case (Reference)
247298

248299
Successfully validated workflow (ID: `cu-fcc-elastic-v3-joint-sdfml`):

apex/skills/apex-flow/reference/calculators.md

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,11 @@ When `interaction.type` is `abacus` or `vasp`, the skill auto-applies smaller su
431431
"interaction": {
432432
"type": "vasp",
433433
"incar": "INCAR",
434-
"potcar_prefix": "/path/to/POTCAR_LIBRARY",
434+
"potcar_prefix": "vasp_potcar",
435435
"potcars": {
436-
"Mo": "Mo_sv",
437-
"Al": "Al",
438-
"Fe": "Fe_pv"
436+
"Mo": "Mo_sv/POTCAR",
437+
"Al": "Al/POTCAR",
438+
"Fe": "Fe_pv/POTCAR"
439439
}
440440
}
441441
}
@@ -485,15 +485,53 @@ LREAL = Auto
485485

486486
### VASP POTCAR Handling
487487

488-
APEX expects POTCAR to be assembled from `potcar_prefix` using the element names in `potcars`. The directory structure should be:
488+
APEX concatenates files at:
489+
490+
```text
491+
os.path.join(potcar_prefix, potcars[element]) # must be a readable FILE
489492
```
493+
494+
Typical VASP potpaw library layout and matching `potcars` values:
495+
496+
```text
490497
/path/to/POTCAR_LIBRARY/
491498
├── Mo_sv/POTCAR
492499
├── Al/POTCAR
493500
├── Fe_pv/POTCAR
494501
└── ...
495502
```
496503

504+
```json
505+
"potcar_prefix": "/path/to/POTCAR_LIBRARY",
506+
"potcars": {
507+
"Mo": "Mo_sv/POTCAR",
508+
"Al": "Al/POTCAR",
509+
"Fe": "Fe_pv/POTCAR"
510+
}
511+
```
512+
513+
Flat files also work (e.g. `"Mo": "POTCAR.Mo"` under `potcar_prefix`).
514+
515+
### Agent check (mandatory when user supplies a POTCAR path)
516+
517+
**Critical:** absolute host paths (e.g. `/share/PAW_PBE`) work only on that
518+
machine. After Bohrium/dflow upload they vanish →
519+
`FileNotFoundError: '/share/PAW_PBE/Ti_pv/POTCAR'`.
520+
521+
Before submit:
522+
523+
1. Confirm the user library exists and is readable locally.
524+
2. For each element, confirm a readable POTCAR file (prefer
525+
`"Ti": "Ti_pv/POTCAR"` for potpaw trees).
526+
3. Use `generate_config.py create --potcar-prefix <lib> --potcars '...'` so
527+
POTCARs are **copied** into the job as `vasp_potcar/` and `param.json` gets
528+
`"potcar_prefix": "vasp_potcar"` (relative). Never ship absolute `/share/...`.
529+
4. Confirm the job directory contains `vasp_potcar/.../POTCAR` before upload.
530+
5. On failure: tell the user the path is unusable and ask for the correct
531+
library. Do not guess.
532+
533+
`scripts/validate_inputs.py` checks that staged relative POTCAR files exist.
534+
497535
---
498536

499537
## Backend Selection Guide

apex/skills/apex-flow/reference/examples.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,8 @@ apex rss rss.json
321321

322322
**Scenario**: Phonon band structure for Si using VASP.
323323

324-
> ⚠️ Requires user to provide VASP image and POTCAR path.
324+
> ⚠️ Requires user to provide VASP image. Stage POTCARs into the job
325+
> (`vasp_potcar/`); do not leave absolute host paths like `/share/PAW_PBE`.
325326
326327
### param.json
327328
```json
@@ -330,8 +331,8 @@ apex rss rss.json
330331
"interaction": {
331332
"type": "vasp",
332333
"incar": "INCAR",
333-
"potcar_prefix": "/opt/vasp/potcar/PBE",
334-
"potcars": {"Si": "Si"}
334+
"potcar_prefix": "vasp_potcar",
335+
"potcars": {"Si": "Si/POTCAR"}
335336
},
336337
"relaxation": {
337338
"cal_setting": {

0 commit comments

Comments
 (0)