Quantum ESPRESSO no-spin SCF calculations (MC3D, k-index)

The converged k-point mesh for 17,757 MC3D structures, measured with Quantum ESPRESSO pw.x self-consistent-field calculations over a k-mesh sweep.

One row per structure: the converged mesh, taken as the first of three consecutive meshes on the structure's k-mesh ladder whose total energies agree within 1 meV per atom. Convergence is judged on energy alone; no force criterion is applied.

No spin polarisation. SSSP PBEsol pseudopotentials. Every mesh is unshifted and therefore Gamma-inclusive.

Files

  • convergence_summary.csv — 17,757 rows, one converged mesh per structure
  • CIF_files.tar.gz — 18,220 structures, CIF_files/<source_db_id>.cif
  • manifest.json — row and structure counts, ladder parameters, file digests
  • LICENSE — CC BY 4.0

The archive holds 18,220 structures while the table has 17,757 rows: 463 structures were calculated but never met the criterion within the range of meshes swept, so they have a structure file and no converged answer. Join on source_db_id and expect the shortfall rather than treating it as missing data.

Columns

  • source_db_id — structure identifier; matches <id>.cif in the archive
  • k_index — 1-based rung on the structure's k-mesh ladder, defined below
  • k_dist_interval — the k-distance interval that maps to k_mesh, in inverse Angstrom, written [upper, lower) with the larger value first
  • k_mesh — the Monkhorst–Pack subdivisions used, as a printed tuple (k1, k2, k3)

k_mesh and k_dist_interval are strings; a loader parses them rather than reading numbers straight out of the column.

A mesh corresponds to an interval of k-distance, not a single value: every k-distance in k_dist_interval yields the same mesh. The interval is written larger value first, because a larger k-distance means a coarser mesh. Rung 1's interval is [inf, x): every k-distance above max(|b_i|) gives (1, 1, 1). If you train on a single k-distance, state which end of the interval you took — the two ends are different numbers for the same mesh.

The k-index

k_index is a position on an ordered ladder of the meshes a structure admits. It is 1-based, and rung 1 is the Gamma-only (1, 1, 1) mesh. Each step up is the next denser mesh the reciprocal lattice admits. Read the base from this record; do not assume it.

The ladder is built from the k-distances at which the mesh changes. With mesh_i = ceil(|b_i| / k_distance) — the VASP KSPACING convention, where |b_i| includes the 2*pi factor — axis i steps from n to n + 1 exactly at k_distance = |b_i| / n. Those quotients, over all three axes, sorted descending, are the only distances where the mesh can change; each interval between neighbours is one rung, and the mesh is read at the interval's midpoint.

The resolution floor. Quotients are enumerated down to min_k_distance = 0.03 inverse Angstrom and no further, so the ladder ends at a mesh of roughly ceil(|b_i| / 0.03) per axis. The floor is the same on every axis, so all three axes stop at the same k-distance: every change point on [0.03, inf) is present, and the ladder is a complete, gap-free set of meshes over that whole range. Consecutive rungs differ by one k-point on at least one axis and never by more than one on any axis.

Repeated meshes are dropped. When two axes have equal |b_i| their change points coincide and two adjacent intervals can yield the same mesh; the ladder keeps that mesh once, so a mesh never takes two k_index values.

k_index in this table spans rungs 1 to 42. Lowering min_k_distance only appends rungs and never renumbers an existing one, so these values stay valid under a smaller floor; a k_index computed under a different floor is comparable only where the two ranges overlap. Any recomputation must state the floor it used.

Reproducing k_index

k_index is reproducible from the structure alone.

import math
from pymatgen.core import Structure

MIN_K_DISTANCE = 0.03


def k_distance_to_mesh(lengths, d):
    return tuple(max(1, math.ceil(round(x / d, 5))) for x in lengths)


def kmesh_ladder(structure, min_k_distance=MIN_K_DISTANCE):
    r = structure.lattice.reciprocal_lattice          # includes 2*pi
    lengths = (r.a, r.b, r.c)
    cands = sorted(
        {
            round(x / n, 8)
            for x in lengths
            for n in range(1, max(1, math.floor(x / min_k_distance)) + 1)
        },
        reverse=True,
    )
    probes = [k_distance_to_mesh(lengths, cands[0] + 1.0)]
    probes += [
        k_distance_to_mesh(lengths, 0.5 * (hi + lo))
        for hi, lo in zip(cands[:-1], cands[1:])
    ]
    ladder, seen = [], set()
    for mesh in probes:
        if mesh in seen:
            continue
        seen.add(mesh)
        ladder.append(mesh)
    return ladder                                     # ladder[i] is rung i + 1


ladder = kmesh_ladder(Structure.from_file("CIF_files/100115.cif"))
assert ladder[0] == (1, 1, 1)
ladder.index((14, 14, 8)) + 1                          # -> 21

The same construction is maintained in stfc/goldilocks-data (goldilocks_data.kmesh) and stfc/goldilocks-core; the sweep and the labelling that produced this table are in goldilocks-data.

Licence

CC BY 4.0. See LICENSE.