ASE Simulation Skill (v1.4)
Always do this first
Before any non-trivial task, run:
python scripts/check_env.py
It prints which calculators and analysis tools are actually installed, and
ends with a one-line "what you can run right now" summary. Recommend a
method that the environment supports — do not ask the user to install xTB if
EMT or LJ already covers the question.
If a backend is missing and the user wants it, prefer the conda install on
HPC / conda systems:
conda install -c conda-forge ase tblite-python mdanalysis matplotlib
…and pip only when conda isn't available:
pip install ase tblite mdanalysis matplotlib
For MACE foundation-model support (v1.2+), install separately:
pip install mace-torch
tblite ships GFN1-xTB and GFN2-xTB and is the supported successor to the
deprecated xtb-python. If check_env.py reports [BROKEN] tblite ... C extension unloadable, the pip wheel is libgfortran-incompatible — switch
to conda install -c conda-forge tblite-python. The standalone xtb
binary (Grimme group) adds GFN0 and GFN-FF if it's on PATH.
mace-torch provides the MACE-MP-0 and MACE-OFF calculators
(element-set routing and the ~1k-atom size cliff are covered in Step-2
rule 6). MACE requires torch; CUDA is strongly recommended (CPU mode
is ~10× slower). check_env.py reports CUDA status and a size-cliff warning.
Method selection
Walk these three steps in order. Each rule names what to do and why; if
the user's case doesn't fit the "because", the rule probably doesn't apply
and you should keep walking.
Step 1 — what task is this?
| Task |
Tool |
Notes |
| Optimize / minimize / relax |
scripts/optimize.py |
FIRE for far-from-equilibrium, BFGS otherwise |
| MD at temperature T |
scripts/run_md.py |
Langevin NVT is the default ensemble |
| Production explicit-solvent MD on a small organic |
scripts/parameterize_gaff2.py then scripts/run_amber.py |
GAFF2 + AM1-BCC, TIP3P/OPC water, min/heat/density/prod via pmemd. See references/amber.md |
| DFT single-point (energy / forces / dipole / charges at DFT level) |
scripts/gaussian_sp.py |
wraps ase.calculators.gaussian.Gaussian; in-house parser for charges/MO. No method/basis defaults — refuse without --method/--basis/--charge/--multiplicity/--mem/--nproc. |
| DFT geometry optimization |
scripts/gaussian_opt.py |
uses GaussianOptimizer (Gaussian L103 — much faster than ASE-BFGS-around-Gaussian-SP). --convergence tight for Freq input. |
| DFT frequency + thermochemistry |
scripts/gaussian_freq.py |
Freq job parsed by in-house _gaussian_log.py helper (no cclib). Tighten the optimization first. |
| Vibrations / Hessian / ZPE (xTB-level) |
ase.vibrations.Vibrations inline |
Optimize to fmax ≤ 0.01 first, or you get spurious imaginary modes |
| HOMO-LUMO / dipole / charges |
scripts/single_point.py (with --calculator xtb) |
Returns gap, dipole, Mulliken charges, bond orders. HOMO-LUMO is the raw eigenvalue gap — see references/xtb.md for the convention. For DFT-level HOMO/LUMO, use gaussian_sp.py. |
| Binding / interaction / adsorption energy |
three runs of scripts/single_point.py (or gaussian_sp.py for DFT) |
E(complex) − E(A) − E(B); use the same calculator for all three |
| Transition state / barrier |
NEB inline (see references/ase_core.md) |
No turnkey script in v1 |
| Build a structure |
ase.build inline |
molecule / bulk / fcc111 / add_adsorbate |
| Analyze a trajectory |
scripts/analyze_traj.py |
RMSD / RMSF / energy drift / optional RDF |
Step 2 — pick the calculator
Apply the first rule that fits the system, in this order:
If the user explicitly named a calculator (xTB, EMT, GFN2, TIP3P,
…), use that one. Why: don't second-guess an explicit choice.
If the system contains only EMT-supported metals (Al, Cu, Ag, Au,
Ni, Pd, Pt, plus H/C/N/O as adsorbates), prefer EMT. Why: it's
free, instant, and the user probably wants a quick metallic-system
answer.
If the system is pure water (H₂O molecules only), the choice
depends on the task:
- Production MD → TIP3P. Why: parameterized for exactly this
case. Requires
ase.constraints.FixBondLengths (rigid-body
model; bare ASE lets the O–H/H–H bonds vibrate and the run blows
up). The bundled scripts do not auto-attach it — add it inline.
See references/ase_core.md §Water (TIP3P + FixBondLengths).
- One-off relaxations or quick energy / single-point checks on
small water systems → GFN2-xTB. Why: simpler — no constraints
to set up — and small water clusters are well within xTB's accuracy
range.
scripts/optimize.py and scripts/single_point.py work as
expected with --calculator xtb.
If the system has organic / main-group chemistry (heteroatoms,
non-EMT elements, organic functional groups, ionic bonding), use
tblite GFN2-xTB. Why: EMT will silently give nonsense for
non-metals; GFN2-xTB is the cheapest method that knows real chemistry.
Sub-rule: if the user wants production-length explicit-solvent MD
(≥ 100 ps in a TIP3P/OPC box) on a single small organic, switch to
GAFF2 + AM1-BCC via scripts/parameterize_gaff2.py →
scripts/run_amber.py. xTB MD with explicit solvent past ~100 ps
is impractical (the box pushes well past 1k atoms once water is
added); GAFF2 is the right tool for that task and the v1.3 scripts
handle the antechamber → tleap → pmemd pipeline. See
references/amber.md for force-field and water-model details.
⚠️ Architecture note (v1.3 Amber). Amber is the only engine in
the skill that does not run through ASE — parameterize_gaff2.py
and run_amber.py shell out to AmberTools and pmemd, and the MD loop
runs natively in pmemd. This is a performance choice, not forced: ASE
exposes a CPU-only in-process path (ase.calculators.amber.SANDER),
but pmemd.cuda is ~10–50× faster on production-sized systems. The
trade is under review (four options open). See references/amber.md
§1 and PLAN.md §"Phase 3", and surface the carve-out when
recommending GAFF2 so the user can decide whether they want it.
If the system is a transition-metal complex and GFN2 fails to
converge, fall back to GFN1-xTB. Why: GFN1 is more robust on
d-block elements at the cost of some accuracy.
If the system is past the xTB size cliff (~1k atoms; xTB MD on a
system that size is impractical past a few ps), reach for a MACE
foundation model. Why: GFN2-xTB MD
stops being practical at 1k atoms; MACE foundation models (MACE-OFF
for organics, MACE-MP-0 for crystals/materials) deliver roughly
DFT-quality energies and forces in that 1k–2k atom range on a
40 GB GPU. Use --calculator mace in optimize.py /
run_md.py; routing is automatic by element set.
Cross-validation against GFN2-xTB is on by default for MD —
every 1 ps the script recomputes E and F on the latest frame
through xTB and aborts the run when MAE_F > 100 meV/Å. This is
the contract under which MACE is recommended at all; do not turn
it off (--no-validate) without a specific reason. Read
references/ml_potentials.md for the full method-selection rules
and known failure modes (liquid mixtures, OOD geometries).
If the system is past the MACE ceiling too (>2k atoms on a
40 GB GPU, >~1k on CPU, or anything past ~50k atoms in v1), say
so out loud: "v1.2 caps at MACE-medium on a single GPU; v2.2 is
slated to add larger ML potentials (CHGNet, Orb) and v2.3 adds
Amber for biomolecular MD beyond GAFF2 small molecules." See
references/ase_core.md §Appendix for the full size table.
If the user explicitly wants DFT (B3LYP, ωB97X-D, M06-2X,
PBE0, post-HF, "publication thermochem", "transition-metal
barriers within 1 kcal/mol", or "compute G298") and Gaussian is
available — use gaussian_sp.py / gaussian_opt.py /
gaussian_freq.py. Why: xTB tops out at ~few-kcal/mol error
on relative energies and is unreliable on transition metals;
DFT is the right tool. No method/basis defaults — surface a
recommendation (ωB97X-D/def2-TZVP for organics; PBE0-D3(BJ)/def2-
TZVP for transition metals; see
references/gaussian_method_selection.md) and
confirm before running. The scripts also require explicit
--charge, --multiplicity, --mem, --nproc. Solvent → SMD by
default. Thermochem parsing is in-house (_gaussian_log.py),
no cclib dependency.
Step 3 — confirm the calculator is installed
Read the [OK] / [MISSING] lines from scripts/check_env.py. If your
chosen calculator is [MISSING], ask the user to install it; do not
silently substitute a wrong-physics fallback. EMT on an organic is the
classic failure mode — it will return numbers that look fine and are
meaningless.
Verification & clarification
Don't ask what's already named — and frame what you do ask
The two failure modes to avoid: silently picking wrong physics (EMT
on an organic returns plausible nonsense; 2 fs timestep without
hydrogen constraints; MACE-OFF on a system with metals; Gaussian
DFT without explicit method/basis), and re-asking the user something
the prompt or structure file already names.
When the answer is genuinely underdetermined, frame the question
with the option you'd pick and the reason — e.g., "GFN2-xTB looks
right here because the system has heteroatoms; want me to fall back
to GFN1 for d-block robustness instead?" — beats a blank "which
method?".
Ask the user to verify before recommending execution
After choosing parameters, restate them in a short block and ask the
user to confirm before suggesting they run anything. The minimum to
surface:
- Calculator (and GFN level if applicable)
- Optimizer / ensemble
- For MD: temperature, friction, timestep, n_steps
- For optimization: fmax, max_steps
- Output paths that will be written
Keep it tight — a 4-6 line summary, not a paragraph. If the user has
already approved the plan, don't re-ask.
Scripts — when to invoke each
All scripts live in scripts/ and are parameterized via argparse.
Run with --help to see options.
Default: call the bundled CLI. Write inline only for a specific,
named capability the script lacks (e.g., "run_md.py has no --barostat,
user asked for NPT") — confirmable via --help. Not justifications:
user phrasing ("write me a script" — the CLI one-liner IS a script),
readability or pedagogy (point at scripts/<name>.py instead), or
tweaks already covered by flags (fmax, timestep, ensemble, calculator,
seed). If the gap is a missing flag, prefer adding the flag over a
one-off rewrite. Name the gap in one sentence before any inline code —
no sentence, no carve-out.
Per-script use:
scripts/check_env.py — Reports installed backends and a
one-line capability summary. Run first on any non-trivial task so you
recommend a method the environment actually supports.
scripts/optimize.py — Geometry optimization with BFGS / FIRE /
LBFGS, calculator EMT / LJ / TIP3P / xTB / MACE. Real-gas LJ via
--epsilon/--sigma/--rc. MACE via --calculator mace
(auto-routed to MACE-OFF for pure organics, MACE-MP-0 otherwise).
scripts/run_md.py — NVE / NVT-Langevin / NVT-Nose-Hoover MD with
EMT / LJ / TIP3P / xTB / MACE. Defaults tuned for organic molecules
(1 fs, 300 K, Langevin friction 0.01/fs, log every 100 steps). With
--calculator mace, GFN2-xTB cross-validation runs by default (the
contract in Step-2 rule 6; flags --validate-every, --abort-mae-f,
--no-validate).
scripts/ml_calculator.py — Helper exposing
make_ml_calc(atoms, system_class=, device=, model_size=). Imported
by optimize.py and run_md.py when --calculator mace. Run as
python scripts/ml_calculator.py --structure mol.xyz to print
routing without loading weights.
scripts/validate_ml_md.py — Post-hoc cross-validation of a saved
MACE trajectory against GFN2-xTB. Same MAE_F threshold as run_md.py
runtime validation; writes validation.csv. For trajectories
produced with --no-validate or to re-validate with a different
reference / stride.
scripts/parameterize_gaff2.py — Drives antechamber -c bcc
(AM1-BCC) → parmchk2 (frcmod) → tleap (solvate in TIP3P/OPC,
neutralize with Na+/Cl-) for a small organic. Output: .prmtop /
.rst7 pair for run_amber.py. Mandatory: --net-charge matches
the formal charge — getting it wrong silently shifts every partial
charge.
scripts/run_amber.py — Runs Amber MD on a .prmtop (--prmtop)
/ .rst7 (--rst, not --rst7) pair. --protocol standard runs
min → heat (50 ps NVT, 0→300 K) → density (100 ps NPT) → prod (default
500 ps NPT). Engine auto-picks pmemd.cuda > pmemd > sander
(--engine). Outputs NetCDF .nc. v1.3 mdin defaults are
GAFF2-tuned (protein/NA prmtops run but may want different
cutoffs/restraints). For Amber-deep workflows (REMD, MMPBSA,
restart/extend, implicit-GB), use amber-chemist instead.
scripts/gaussian_sp.py — DFT single-point E/F/dipole via
ase.calculators.gaussian.Gaussian (g09 fallback). Mulliken charges
and HOMO/LUMO parsed by _gaussian_log.py. Required flags + SMD
default per Step-2 rule 8 — no silent defaults.
scripts/gaussian_opt.py — DFT geometry optimization via
GaussianOptimizer (Gaussian's L103, one g16/g09 invocation).
--convergence is a string (loose/default/tight/verytight),
not a numeric eV/Å. Use tight or verytight if the optimized
geometry feeds into a Freq job.
scripts/gaussian_freq.py — DFT frequency + thermochemistry
(vib_freqs / ZPE / enthalpy / Gibbs G) via _gaussian_log.py. Reports
imaginary modes (warning + nonzero exit). Freq method/basis must
match the optimization — not enforced; surface it.
scripts/_gaussian_log.py — Helper module: regex parsers for
Gaussian .log fields ASE doesn't cover (vib_freqs, thermochem,
Mulliken charges, MO eigenvalues). Imported by gaussian_sp.py and
gaussian_freq.py. Stdlib-only.
scripts/single_point.py — Single-point energy plus xTB
electronic observables (dipole, Mulliken charges, Wiberg bond
orders, HOMO-LUMO raw eigenvalue gap). Tagged key=value output.
Optimize first — single-point observables on a strained geometry are
nonsense. For binding-energy decomposition, run three times.
scripts/analyze_traj.py — RMSD, RMSF, energy drift, optional
RDF from a trajectory. Saves PNG plots and CSV data alongside the
input. These analyses ARE the script's primary purpose — do not
write a substitute for any of them inline. Handles edge cases
(Kabsch alignment, missing-calculator fallback for energy drift,
periodic unwrapping for RDF) that an inline rewrite will get wrong.
Growing the skill: when to offer to bundle new scripts
When inline code looks like recurring work, offer to promote it to a
bundled script. Offer only when all hold: the code is substantial
(>~30 lines or a parametric workflow), no existing scripts/ entry
covers it, and the request reads as recurring ("for each molecule",
"every time I get a new structure"). Don't offer for trivial one-shots,
already-covered tasks, or exploratory/definitional questions.
If the user says yes: refactor into scripts/<verb>.py (naming like
optimize.py / run_md.py) with argparse + a top-of-file docstring
saying when to reach for it, match output conventions (banner, tagged
[OK] / [INFO] lines, plots/CSVs alongside input, meaningful exit
codes), add a one-line SKILL.md §Scripts bullet, and verify with
--help + one example. If no, leave it and don't re-ask this session.
References — read these on demand
Each file is short and topic-scoped; read the one whose topic comes up.
references/ase_core.md — structure I/O, ase.build, optimizers, MD integrators, units, Trajectory format, NEB scaffolding.
references/xtb.md — tblite install, GFN1 vs GFN2, the standalone xtb binary (GFN0/GFN-FF), xTB observables, limitations.
references/analysis.md — ASE readers vs MDAnalysis, recipes for the analyze_traj.py analyses, pitfalls.
references/ml_potentials.md — MACE vs xTB, the cross-validation contract, MACE failure modes, the GPU ceiling, troubleshooting.
references/amber.md — when GAFF2 wins, the antechamber→parmchk2→tleap→pmemd pipeline, force-field/water choices, engine selection, failure modes. Protein/NA (ff19SB/OL21) deferred to v2.3.
references/gaussian.md — when Gaussian beats xTB, the no-defaults policy + recommended method/basis, SMD vs PCM, g16/g09, the _gaussian_log.py parser, failure modes. Opt=TS/IRC/NBO/TDDFT/post-HF deferred to v3+.
Smell test — don't fabricate technical semantics. If you are
about to write "I think <keyword> defaults to ..." or "the
standard value for <flag> is roughly ..." — for a Gaussian route
line, an xTB GFN convention, a MACE element-set rule, an Amber mdin
keyword, or any other domain-specific knob — stop and check the
right reference file (or its upstream manual). Hallucinated semantics
is a high-cost, hard-to-detect failure mode because the calculation
often runs with the wrong value and produces plausible-looking
output.
Defaults and conventions
- Units: ASE uses eV, Å, ASE-time-units. Use
ase.units.fs /
ase.units.kB rather than raw numbers. Temperature kwarg is
temperature_K= (canonical since ASE 3.21.0).
- Timestep: 1 fs is safe for organic molecules with all-atom dynamics.
Bump to 2 fs only if you constrain hydrogen bonds (ASE doesn't do
RATTLE/SHAKE elegantly, so 1 fs is the safer default).
- Friction (Langevin): 0.01 / fs is a reasonable thermostat coupling
for production. Higher values (0.1 / fs) for fast equilibration.
- Nose-Hoover coupling:
--tdamp 100 fs is the default characteristic
timescale for the deterministic nvt-nose-hoover thermostat in run_md.py.
- Optimization tolerance:
fmax=0.05 eV/Å for production geometries;
0.01 eV/Å for vibrational analysis input.
- Trajectory format: prefer
.traj (ASE binary, includes calculator
results) over .xyz (positions only) when energies/forces matter
downstream.
- Random seed: Set
seed in MD integrators if reproducibility matters
to the user.
Reporting results
When you finish a task, report:
- The method used (calculator + integrator/optimizer) and why it was
chosen given system size, available backends, and accuracy needed.
- Final numbers (energy, fmax, temperature, etc.) with units.
- Where outputs were written (trajectory, plots, CSVs).
- Any caveats (e.g., "GFN2-xTB; transition-metal accuracy is limited",
"NVE energy drift was 0.3 meV/atom over 1 ps — reasonable").
What v1 does NOT support
Be honest about scope. Deferrals:
- Biopolymer Amber MD (ff19SB+OPC / OL21) → v2.3. BYO-prmtop runs work
with
run_amber.py but mdin defaults are GAFF2-tuned — flag the
mismatch.
- Gaussian
Opt=TS / QST / IRC, anharmonic Freq, NBO/NPA, post-HF
(CCSD/MP2/CASSCF), excited states (TDDFT/CIS/EOM-CCSD) → v3+; see
references/gaussian_failure_modes.md §"Out of scope". (Method strings pass to Gaussian
verbatim, so a post-HF route runs, but gets no method-specific
parsing or validation — prefer DFT.)
- ML potentials beyond MACE (CHGNet, Orb-v3, M3GNet, SevenNet) →
v2.2+; MACE-MP-0 covers most of the same scope today (see
references/ml_potentials.md).
- VASP, Quantum ESPRESSO → no v2 plan; CP2K / FHI-aims bridges may
land in v3.
- Free-energy (TI/FEP/MBAR), enhanced sampling (REMD, metadynamics,
umbrella), QM/MM, constant-pH.
- RESP charges via Gaussian — AM1-BCC only in v1.3.
- SLURM submission scripts; web GUI / visualization servers.
1---2name: ase-chemist3description: ASE Simulation Skill (v1.4)4---56# ASE Simulation Skill (v1.4)78## Always do this first910Before any non-trivial task, run:1112```bash13python scripts/check_env.py14```1516It prints which calculators and analysis tools are actually installed, and17ends with a one-line "what you can run right now" summary. **Recommend a18method that the environment supports** — do not ask the user to install xTB if19EMT or LJ already covers the question.2021If a backend is missing and the user wants it, prefer the conda install on22HPC / conda systems:2324```bash25conda install -c conda-forge ase tblite-python mdanalysis matplotlib26```2728…and pip only when conda isn't available:2930```bash31pip install ase tblite mdanalysis matplotlib32```3334For MACE foundation-model support (v1.2+), install separately:3536```bash37pip install mace-torch38```3940`tblite` ships GFN1-xTB and GFN2-xTB and is the supported successor to the41deprecated `xtb-python`. If `check_env.py` reports `[BROKEN] tblite ...42C extension unloadable`, the pip wheel is libgfortran-incompatible — switch43to `conda install -c conda-forge tblite-python`. The standalone `xtb`44binary (Grimme group) adds GFN0 and GFN-FF if it's on PATH.4546`mace-torch` provides the **MACE-MP-0** and **MACE-OFF** calculators47(element-set routing and the ~1k-atom size cliff are covered in Step-248rule 6). MACE requires `torch`; CUDA is strongly recommended (CPU mode49is ~10× slower). `check_env.py` reports CUDA status and a size-cliff warning.5051## Method selection5253Walk these three steps in order. Each rule names *what* to do and *why*; if54the user's case doesn't fit the "because", the rule probably doesn't apply55and you should keep walking.5657### Step 1 — what task is this?5859| Task | Tool | Notes |60|---|---|---|61| Optimize / minimize / relax | `scripts/optimize.py` | FIRE for far-from-equilibrium, BFGS otherwise |62| MD at temperature T | `scripts/run_md.py` | Langevin NVT is the default ensemble |63| Production explicit-solvent MD on a small organic | `scripts/parameterize_gaff2.py` then `scripts/run_amber.py` | GAFF2 + AM1-BCC, TIP3P/OPC water, min/heat/density/prod via pmemd. See `references/amber.md` |64| **DFT single-point** (energy / forces / dipole / charges at DFT level) | `scripts/gaussian_sp.py` | wraps `ase.calculators.gaussian.Gaussian`; in-house parser for charges/MO. **No method/basis defaults — refuse without `--method`/`--basis`/`--charge`/`--multiplicity`/`--mem`/`--nproc`.** |65| **DFT geometry optimization** | `scripts/gaussian_opt.py` | uses `GaussianOptimizer` (Gaussian L103 — much faster than ASE-BFGS-around-Gaussian-SP). `--convergence tight` for Freq input. |66| **DFT frequency + thermochemistry** | `scripts/gaussian_freq.py` | Freq job parsed by in-house `_gaussian_log.py` helper (no cclib). Tighten the optimization first. |67| Vibrations / Hessian / ZPE (xTB-level) | `ase.vibrations.Vibrations` inline | Optimize to fmax ≤ 0.01 first, or you get spurious imaginary modes |68| HOMO-LUMO / dipole / charges | `scripts/single_point.py` (with `--calculator xtb`) | Returns gap, dipole, Mulliken charges, bond orders. **HOMO-LUMO is the raw eigenvalue gap — see `references/xtb.md` for the convention.** For DFT-level HOMO/LUMO, use `gaussian_sp.py`. |69| Binding / interaction / adsorption energy | three runs of `scripts/single_point.py` (or `gaussian_sp.py` for DFT) | E(complex) − E(A) − E(B); use the same calculator for all three |70| Transition state / barrier | NEB inline (see `references/ase_core.md`) | No turnkey script in v1 |71| Build a structure | `ase.build` inline | molecule / bulk / fcc111 / add_adsorbate |72| Analyze a trajectory | `scripts/analyze_traj.py` | RMSD / RMSF / energy drift / optional RDF |7374### Step 2 — pick the calculator7576Apply the first rule that fits the system, in this order:77781. **If the user explicitly named a calculator** (xTB, EMT, GFN2, TIP3P,79 …), use that one. *Why:* don't second-guess an explicit choice.802. **If the system contains only EMT-supported metals** (Al, Cu, Ag, Au,81 Ni, Pd, Pt, plus H/C/N/O as adsorbates), prefer **EMT**. *Why:* it's82 free, instant, and the user probably wants a quick metallic-system83 answer.843. **If the system is pure water** (H₂O molecules only), the choice85 depends on the task:86 - **Production MD** → **TIP3P**. *Why:* parameterized for exactly this87 case. **Requires `ase.constraints.FixBondLengths`** (rigid-body88 model; bare ASE lets the O–H/H–H bonds vibrate and the run blows89 up). The bundled scripts do **not** auto-attach it — add it inline.90 See `references/ase_core.md` §Water (TIP3P + FixBondLengths).91 - **One-off relaxations or quick energy / single-point checks** on92 small water systems → **GFN2-xTB**. *Why:* simpler — no constraints93 to set up — and small water clusters are well within xTB's accuracy94 range. `scripts/optimize.py` and `scripts/single_point.py` work as95 expected with `--calculator xtb`.964. **If the system has organic / main-group chemistry** (heteroatoms,97 non-EMT elements, organic functional groups, ionic bonding), use98 **tblite GFN2-xTB**. *Why:* EMT will silently give nonsense for99 non-metals; GFN2-xTB is the cheapest method that knows real chemistry.100 *Sub-rule: if the user wants production-length explicit-solvent MD101 (≥ 100 ps in a TIP3P/OPC box) on a single small organic, switch to102 **GAFF2 + AM1-BCC** via `scripts/parameterize_gaff2.py` →103 `scripts/run_amber.py`. xTB MD with explicit solvent past ~100 ps104 is impractical (the box pushes well past 1k atoms once water is105 added); GAFF2 is the right tool for that task and the v1.3 scripts106 handle the antechamber → tleap → pmemd pipeline. See107 `references/amber.md` for force-field and water-model details.*108109 > **⚠️ Architecture note (v1.3 Amber).** Amber is the **only engine in110 > the skill that does not run through ASE** — `parameterize_gaff2.py`111 > and `run_amber.py` shell out to AmberTools and pmemd, and the MD loop112 > runs natively in pmemd. This is a performance choice, not forced: ASE113 > exposes a CPU-only in-process path (`ase.calculators.amber.SANDER`),114 > but pmemd.cuda is ~10–50× faster on production-sized systems. The115 > trade is under review (four options open). See `references/amber.md`116 > §1 and `PLAN.md` §"Phase 3", and surface the carve-out when117 > recommending GAFF2 so the user can decide whether they want it.1185. **If the system is a transition-metal complex and GFN2 fails to119 converge**, fall back to **GFN1-xTB**. *Why:* GFN1 is more robust on120 d-block elements at the cost of some accuracy.1216. **If the system is past the xTB size cliff (~1k atoms; xTB MD on a122 system that size is impractical past a few ps), reach for a MACE123 foundation model.** *Why:* GFN2-xTB MD124 stops being practical at ~1k atoms; MACE foundation models (MACE-OFF125 for organics, MACE-MP-0 for crystals/materials) deliver roughly126 DFT-quality energies and forces in that 1k–~2k atom range on a127 40 GB GPU. Use `--calculator mace` in `optimize.py` /128 `run_md.py`; routing is automatic by element set.129 **Cross-validation against GFN2-xTB is on by default for MD** —130 every 1 ps the script recomputes E and F on the latest frame131 through xTB and aborts the run when MAE_F > 100 meV/Å. This is132 the contract under which MACE is recommended at all; do not turn133 it off (`--no-validate`) without a specific reason. Read134 `references/ml_potentials.md` for the full method-selection rules135 and known failure modes (liquid mixtures, OOD geometries).1367. **If the system is past the MACE ceiling too** (>2k atoms on a137 40 GB GPU, >~1k on CPU, or anything past ~50k atoms in v1), say138 so out loud: "v1.2 caps at MACE-medium on a single GPU; v2.2 is139 slated to add larger ML potentials (CHGNet, Orb) and v2.3 adds140 Amber for biomolecular MD beyond GAFF2 small molecules." See141 `references/ase_core.md` §Appendix for the full size table.1428. **If the user explicitly wants DFT** (B3LYP, ωB97X-D, M06-2X,143 PBE0, post-HF, "publication thermochem", "transition-metal144 barriers within 1 kcal/mol", or "compute G298") and Gaussian is145 available — use **`gaussian_sp.py` / `gaussian_opt.py` /146 `gaussian_freq.py`**. *Why:* xTB tops out at ~few-kcal/mol error147 on relative energies and is unreliable on transition metals;148 DFT is the right tool. **No method/basis defaults** — surface a149 recommendation (ωB97X-D/def2-TZVP for organics; PBE0-D3(BJ)/def2-150 TZVP for transition metals; see151 `references/gaussian_method_selection.md`) and152 confirm before running. The scripts also require explicit153 `--charge`, `--multiplicity`, `--mem`, `--nproc`. Solvent → SMD by154 default. Thermochem parsing is in-house (`_gaussian_log.py`),155 no cclib dependency.156157### Step 3 — confirm the calculator is installed158159Read the `[OK]` / `[MISSING]` lines from `scripts/check_env.py`. If your160chosen calculator is `[MISSING]`, ask the user to install it; **do not161silently substitute a wrong-physics fallback**. EMT on an organic is the162classic failure mode — it will return numbers that look fine and are163meaningless.164165## Verification & clarification166167### Don't ask what's already named — and frame what you do ask168169The two failure modes to avoid: silently picking wrong physics (EMT170on an organic returns plausible nonsense; 2 fs timestep without171hydrogen constraints; MACE-OFF on a system with metals; Gaussian172DFT without explicit method/basis), and re-asking the user something173the prompt or structure file already names.174175When the answer is genuinely underdetermined, frame the question176with the option you'd pick and the reason — e.g., *"GFN2-xTB looks177right here because the system has heteroatoms; want me to fall back178to GFN1 for d-block robustness instead?"* — beats a blank "which179method?".180181### Ask the user to verify before recommending execution182183After choosing parameters, restate them in a short block and ask the184user to confirm before suggesting they run anything. The minimum to185surface:186187- Calculator (and GFN level if applicable)188- Optimizer / ensemble189- For MD: temperature, friction, timestep, n_steps190- For optimization: fmax, max_steps191- Output paths that will be written192193Keep it tight — a 4-6 line summary, not a paragraph. If the user has194already approved the plan, don't re-ask.195196## Scripts — when to invoke each197198All scripts live in `scripts/` and are parameterized via argparse.199Run with `--help` to see options.200201**Default: call the bundled CLI.** Write inline only for a *specific,202named* capability the script lacks (e.g., "run_md.py has no `--barostat`,203user asked for NPT") — confirmable via `--help`. Not justifications:204user phrasing ("write me a script" — the CLI one-liner IS a script),205readability or pedagogy (point at `scripts/<name>.py` instead), or206tweaks already covered by flags (fmax, timestep, ensemble, calculator,207seed). If the gap is a missing flag, prefer adding the flag over a208one-off rewrite. Name the gap in one sentence before any inline code —209no sentence, no carve-out.210211Per-script use:212213- **`scripts/check_env.py`** — Reports installed backends and a214 one-line capability summary. Run first on any non-trivial task so you215 recommend a method the environment actually supports.216- **`scripts/optimize.py`** — Geometry optimization with BFGS / FIRE /217 LBFGS, calculator EMT / LJ / TIP3P / xTB / MACE. Real-gas LJ via218 `--epsilon`/`--sigma`/`--rc`. MACE via `--calculator mace`219 (auto-routed to MACE-OFF for pure organics, MACE-MP-0 otherwise).220- **`scripts/run_md.py`** — NVE / NVT-Langevin / NVT-Nose-Hoover MD with221 EMT / LJ / TIP3P / xTB / MACE. Defaults tuned for organic molecules222 (1 fs, 300 K, Langevin friction 0.01/fs, log every 100 steps). With223 `--calculator mace`, GFN2-xTB cross-validation runs by default (the224 contract in Step-2 rule 6; flags `--validate-every`, `--abort-mae-f`,225 `--no-validate`).226- **`scripts/ml_calculator.py`** — Helper exposing227 `make_ml_calc(atoms, system_class=, device=, model_size=)`. Imported228 by `optimize.py` and `run_md.py` when `--calculator mace`. Run as229 `python scripts/ml_calculator.py --structure mol.xyz` to print230 routing without loading weights.231- **`scripts/validate_ml_md.py`** — Post-hoc cross-validation of a saved232 MACE trajectory against GFN2-xTB. Same MAE_F threshold as `run_md.py`233 runtime validation; writes `validation.csv`. For trajectories234 produced with `--no-validate` or to re-validate with a different235 reference / stride.236- **`scripts/parameterize_gaff2.py`** — Drives `antechamber -c bcc`237 (AM1-BCC) → `parmchk2` (frcmod) → `tleap` (solvate in TIP3P/OPC,238 neutralize with Na+/Cl-) for a small organic. Output: `.prmtop` /239 `.rst7` pair for `run_amber.py`. **Mandatory: `--net-charge` matches240 the formal charge** — getting it wrong silently shifts every partial241 charge.242- **`scripts/run_amber.py`** — Runs Amber MD on a `.prmtop` (`--prmtop`)243 / `.rst7` (`--rst`, not `--rst7`) pair. `--protocol standard` runs244 min → heat (50 ps NVT, 0→300 K) → density (100 ps NPT) → prod (default245 500 ps NPT). Engine auto-picks `pmemd.cuda` > `pmemd` > `sander`246 (`--engine`). Outputs NetCDF `.nc`. v1.3 `mdin` defaults are247 GAFF2-tuned (protein/NA prmtops run but may want different248 cutoffs/restraints). For Amber-deep workflows (REMD, MMPBSA,249 restart/extend, implicit-GB), use `amber-chemist` instead.250- **`scripts/gaussian_sp.py`** — DFT single-point E/F/dipole via251 `ase.calculators.gaussian.Gaussian` (g09 fallback). Mulliken charges252 and HOMO/LUMO parsed by `_gaussian_log.py`. Required flags + SMD253 default per Step-2 rule 8 — no silent defaults.254- **`scripts/gaussian_opt.py`** — DFT geometry optimization via255 `GaussianOptimizer` (Gaussian's L103, one g16/g09 invocation).256 `--convergence` is a string (`loose`/`default`/`tight`/`verytight`),257 not a numeric eV/Å. Use `tight` or `verytight` if the optimized258 geometry feeds into a Freq job.259- **`scripts/gaussian_freq.py`** — DFT frequency + thermochemistry260 (vib_freqs / ZPE / enthalpy / Gibbs G) via `_gaussian_log.py`. Reports261 imaginary modes (warning + nonzero exit). **Freq method/basis must262 match the optimization** — not enforced; surface it.263- **`scripts/_gaussian_log.py`** — Helper module: regex parsers for264 Gaussian .log fields ASE doesn't cover (vib_freqs, thermochem,265 Mulliken charges, MO eigenvalues). Imported by gaussian_sp.py and266 gaussian_freq.py. Stdlib-only.267- **`scripts/single_point.py`** — Single-point energy plus xTB268 electronic observables (dipole, Mulliken charges, Wiberg bond269 orders, HOMO-LUMO raw eigenvalue gap). Tagged `key=value` output.270 Optimize first — single-point observables on a strained geometry are271 nonsense. For binding-energy decomposition, run three times.272- **`scripts/analyze_traj.py`** — RMSD, RMSF, energy drift, optional273 RDF from a trajectory. Saves PNG plots and CSV data alongside the274 input. **These analyses ARE the script's primary purpose — do not275 write a substitute for any of them inline.** Handles edge cases276 (Kabsch alignment, missing-calculator fallback for energy drift,277 periodic unwrapping for RDF) that an inline rewrite will get wrong.278279### Growing the skill: when to offer to bundle new scripts280281When inline code looks like recurring work, offer to promote it to a282bundled script. **Offer only when all hold:** the code is substantial283(>~30 lines or a parametric workflow), no existing `scripts/` entry284covers it, and the request reads as recurring ("for each molecule",285"every time I get a new structure"). Don't offer for trivial one-shots,286already-covered tasks, or exploratory/definitional questions.287288If the user says yes: refactor into `scripts/<verb>.py` (naming like289`optimize.py` / `run_md.py`) with argparse + a top-of-file docstring290saying *when* to reach for it, match output conventions (banner, tagged291`[OK]` / `[INFO]` lines, plots/CSVs alongside input, meaningful exit292codes), add a one-line SKILL.md §Scripts bullet, and verify with293`--help` + one example. If no, leave it and don't re-ask this session.294295## References — read these on demand296297Each file is short and topic-scoped; read the one whose topic comes up.298299- **`references/ase_core.md`** — structure I/O, `ase.build`, optimizers, MD integrators, units, Trajectory format, NEB scaffolding.300- **`references/xtb.md`** — tblite install, GFN1 vs GFN2, the standalone `xtb` binary (GFN0/GFN-FF), xTB observables, limitations.301- **`references/analysis.md`** — ASE readers vs MDAnalysis, recipes for the `analyze_traj.py` analyses, pitfalls.302- **`references/ml_potentials.md`** — MACE vs xTB, the cross-validation contract, MACE failure modes, the GPU ceiling, troubleshooting.303- **`references/amber.md`** — when GAFF2 wins, the antechamber→parmchk2→tleap→pmemd pipeline, force-field/water choices, engine selection, failure modes. Protein/NA (ff19SB/OL21) deferred to v2.3.304- **`references/gaussian.md`** — when Gaussian beats xTB, the no-defaults policy + recommended method/basis, SMD vs PCM, g16/g09, the `_gaussian_log.py` parser, failure modes. Opt=TS/IRC/NBO/TDDFT/post-HF deferred to v3+.305306**Smell test — don't fabricate technical semantics.** If you are307about to write *"I think `<keyword>` defaults to ..."* or *"the308standard value for `<flag>` is roughly ..."* — for a Gaussian route309line, an xTB GFN convention, a MACE element-set rule, an Amber mdin310keyword, or any other domain-specific knob — stop and check the311right reference file (or its upstream manual). Hallucinated semantics312is a high-cost, hard-to-detect failure mode because the calculation313often *runs* with the wrong value and produces plausible-looking314output.315316## Defaults and conventions317318- **Units**: ASE uses eV, Å, ASE-time-units. Use `ase.units.fs` /319 `ase.units.kB` rather than raw numbers. Temperature kwarg is320 `temperature_K=` (canonical since ASE 3.21.0).321- **Timestep**: 1 fs is safe for organic molecules with all-atom dynamics.322 Bump to 2 fs only if you constrain hydrogen bonds (ASE doesn't do323 RATTLE/SHAKE elegantly, so 1 fs is the safer default).324- **Friction (Langevin)**: 0.01 / fs is a reasonable thermostat coupling325 for production. Higher values (0.1 / fs) for fast equilibration.326- **Nose-Hoover coupling**: `--tdamp 100 fs` is the default characteristic327 timescale for the deterministic `nvt-nose-hoover` thermostat in `run_md.py`.328- **Optimization tolerance**: `fmax=0.05 eV/Å` for production geometries;329 `0.01 eV/Å` for vibrational analysis input.330- **Trajectory format**: prefer `.traj` (ASE binary, includes calculator331 results) over `.xyz` (positions only) when energies/forces matter332 downstream.333- **Random seed**: Set `seed` in MD integrators if reproducibility matters334 to the user.335336## Reporting results337338When you finish a task, report:3391. The method used (calculator + integrator/optimizer) and **why** it was340 chosen given system size, available backends, and accuracy needed.3412. Final numbers (energy, fmax, temperature, etc.) with units.3423. Where outputs were written (trajectory, plots, CSVs).3434. Any caveats (e.g., "GFN2-xTB; transition-metal accuracy is limited",344 "NVE energy drift was 0.3 meV/atom over 1 ps — reasonable").345346## What v1 does NOT support347348Be honest about scope. Deferrals:349- Biopolymer Amber MD (ff19SB+OPC / OL21) → v2.3. BYO-prmtop runs work350 with `run_amber.py` but `mdin` defaults are GAFF2-tuned — flag the351 mismatch.352- Gaussian `Opt=TS` / QST / IRC, anharmonic Freq, NBO/NPA, post-HF353 (CCSD/MP2/CASSCF), excited states (TDDFT/CIS/EOM-CCSD) → v3+; see354 `references/gaussian_failure_modes.md` §"Out of scope". (Method strings pass to Gaussian355 verbatim, so a post-HF route *runs*, but gets no method-specific356 parsing or validation — prefer DFT.)357- ML potentials beyond MACE (CHGNet, Orb-v3, M3GNet, SevenNet) →358 v2.2+; MACE-MP-0 covers most of the same scope today (see359 `references/ml_potentials.md`).360- VASP, Quantum ESPRESSO → no v2 plan; CP2K / FHI-aims bridges may361 land in v3.362- Free-energy (TI/FEP/MBAR), enhanced sampling (REMD, metadynamics,363 umbrella), QM/MM, constant-pH.364- RESP charges via Gaussian — AM1-BCC only in v1.3.365- SLURM submission scripts; web GUI / visualization servers.