Convergence Testing

SkillDev tools

Before production calculations, verify that results are converged with respect to key numerical parameters. The two most important are:

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Convergence Testing skill

About this capability

Use when the user asks to test ENCUT convergence, k-point convergence, or any parameter sweep to determine converged computational settings.

What this skill tells your AI

The instructions your AI receives, as published by hello-qm/catgo-lrg in .claude/skills/convergence-test/SKILL.md and read by ahel’s review.

Purpose

Before production calculations, verify that results are converged with respect to key numerical parameters. The two most important are:

  1. ENCUT (planewave cutoff energy) -- controls basis set completeness
  2. KPOINTS (k-point mesh density) -- controls Brillouin zone sampling

Convergence is reached when the target property (energy, forces, band gap) changes by less than a threshold (typically 1 meV/atom for energy).

Fan-Out Pattern

Convergence tests use a fan-out DAG: one input structure feeds into multiple independent single_point calculations with different parameter values.

                   +--> single_point(ENCUT=300)
                   |
structure_input ---+--> single_point(ENCUT=400)
                   |
                   +--> single_point(ENCUT=500)
                   |
                   +--> single_point(ENCUT=600)
                   |
                   +--> single_point(ENCUT=700)

Use single_point (not geo_opt) to isolate the parameter effect without geometry changes confounding the comparison.

MCP Workflow: ENCUT Convergence

Step 1: Create workflow

{"tool": "catgo_workflow_engine", "arguments": {
  "action": "create", "name": "ENCUT convergence - TiO2"
}}

Step 2: Add single_point tasks at each ENCUT

{"tool": "catgo_workflow_engine", "arguments": {
  "action": "add_task", "workflow_id": "wf_conv",
  "task_type": "single_point",
  "params": {"software": "vasp", "ENCUT": 300, "system_name": "ENCUT=300"}
}}
{"tool": "catgo_workflow_engine", "arguments": {
  "action": "add_task", "workflow_id": "wf_conv",
  "task_type": "single_point",
  "params": {"software": "vasp", "ENCUT": 400, "system_name": "ENCUT=400"}
}}
{"tool": "catgo_workflow_engine", "arguments": {
  "action": "add_task", "workflow_id": "wf_conv",
  "task_type": "single_point",
  "params": {"software": "vasp", "ENCUT": 500, "system_name": "ENCUT=500"}
}}

Repeat for ENCUT = 600, 700, 800.

Step 3: Submit

{"tool": "catgo_workflow_engine", "arguments": {
  "action": "submit", "workflow_id": "wf_conv"
}}

Step 4: Check results

{"tool": "catgo_workflow_engine", "arguments": {
  "action": "get_result", "workflow_id": "wf_conv", "task_id": "task_encut300"
}}
{"tool": "catgo_analyze", "arguments": {
  "action": "convergence", "workflow_id": "wf_conv"
}}

MCP Workflow: KPOINTS Convergence

{"tool": "catgo_workflow_engine", "arguments": {
  "action": "add_task", "workflow_id": "wf_conv",
  "task_type": "single_point",
  "params": {"software": "vasp", "ENCUT": 520, "KPOINTS": [2,2,1],
             "system_name": "2x2x1"}
}}
{"tool": "catgo_workflow_engine", "arguments": {
  "action": "add_task", "workflow_id": "wf_conv",
  "task_type": "single_point",
  "params": {"software": "vasp", "ENCUT": 520, "KPOINTS": [4,4,1],
             "system_name": "4x4x1"}
}}

Repeat for 6x6x1, 8x8x1. Use the converged ENCUT from the previous test.

Python API

ENCUT Convergence

from catgo.workflow import Workflow

wf = Workflow("ENCUT convergence - TiO2")
inp = wf.add_task("structure_input", structure=tio2_json)

encut_values = [300, 400, 500, 600, 700, 800]
tasks = {}
for encut in encut_values:
    tasks[encut] = wf.add_task("single_point",
        structure=inp.output.structure,
        software="vasp", ENCUT=encut,
        system_name=f"ENCUT={encut}")

wf.submit()

KPOINTS Convergence

wf = Workflow("KPOINTS convergence - TiO2 slab")
inp = wf.add_task("structure_input", structure=tio2_slab_json)

kpoints_list = [[2,2,1], [4,4,1], [6,6,1], [8,8,1], [10,10,1]]
for kp in kpoints_list:
    label = f"{kp[0]}x{kp[1]}x{kp[2]}"
    wf.add_task("single_point",
        structure=inp.output.structure,
        software="vasp", ENCUT=520, KPOINTS=kp,
        system_name=label)

wf.submit()

Convergence Criteria

PropertyThresholdTypical Converged ENCUT
Total energy1 meV/atom1.3x max(ENMAX) in POTCAR
Forces5 meV/ASame as energy
Band gap10 meVMay need higher ENCUT
Stress tensor0.1 kbarOften needs 1.5x ENMAX

Recommended ENCUT Values by Element Type

SystemStarting ENCUT RangeNotes
Simple metals (Cu, Pt)300-500Usually converges quickly
Oxides (TiO2, RuO2)400-600O has high ENMAX
Nitrides, carbides400-600N, C have moderate ENMAX
F-containing500-800F has very high ENMAX

Two-Stage Strategy

  1. ENCUT first: Fix KPOINTS at a moderate value (e.g., 4x4x4), sweep ENCUT. Pick the converged ENCUT.
  2. KPOINTS second: Fix ENCUT at converged value, sweep KPOINTS. Pick the converged mesh.

This avoids the combinatorial explosion of testing all ENCUT x KPOINTS pairs.

Common Pitfalls

  1. Always use single_point, not geo_opt. Geometry changes at different ENCUT introduce noise that masks the convergence behavior.
  2. For slab models, only converge the in-plane k-points (e.g., NxNx1). The vacuum direction needs only 1 k-point.
  3. ENCUT should be at least 1.3x the maximum ENMAX in the POTCAR. Check POTCAR ENMAX values before choosing the test range.
  4. Report energy per atom (E_total / N_atoms), not total energy, for meaningful comparison across different systems.
  5. Always plot E vs parameter -- convergence should be monotonic. Non-monotonic behavior suggests other issues (e.g., SCF convergence).

Signals

GitHub stars
196
Forks
23
Last commit
Sep 2026

ahel recommends instead

Advanced
Catalog kind
skill
Gateway key
convergence-test-hello-qm
Source
github.com/hello-qm/catgo-lrg