Skip to content

lmf,lmfa,lmchk

⚠️ TOML migration (2026-05)lmf, lmfa, lmchk now read ctrlg.<sname>.toml + PB.<sname>.toml only. The ctrl.<sname> examples below are legacy syntax kept as developer reference; convert with Legacy2toml.py <sname> before invoking these binaries. See TOML migration for the full guide and migrated Samples/.

We need an input file ctrlg.<sname>.toml (legacy: ctrl.<sname>).
<sname> is the positional argument passed to the binary (e.g. lmf si reads ctrlg.si.toml); the rest of this page uses <sname> as a placeholder for whatever material extension the user chose at Legacy2toml.py / ctrlgenToml.py time.

lmfa: spherical atom calculations

Example:`

lmfa si

It finishes instantaneously.

lmfa si |grep conf

shows electronic configurations. It gives electron densities of spherical atoms contained in the primitive cell specified by . With the superposition of the densities From which, we construct initial electronic density for lmf. In addition,lmfa generates

lmchk: Check crystal symmetry.

lmchk gives useful information of space group symmetry recognized by lmf. In addition, it determines MT radius.The space-group operations are explained at SYMGRP.

MT radius determined by lmchk

The ideal choice of sphere radii best approximates a potential that is spherical within the MT spheres and flat outside. Program lmchk has implemented one algorithm that makes a reasonable initial choice for MT radii. The algorithm works by computing the (electrostatic) potential obtained from overlapping free-atom densities along all connecting vectors between a given site and its relatively near neighbors. The MT radius is taken as the first potential maximum along any ray. This choice is a pretty reasonable estimate for the potential being approximately spherical inside. Also, note that for a completely symmetric bond, the potential maximum will fall exactly midway between the bond, so for that case the two sphere radii will exactly touch and have equal potentials. To tell lmchk to find these radii, invoke lmchk as lmchk --getwsr. This is performed automatically in ctrlgenToml.py (and the legacy ctrlgenM1.py).

  • In addition, ctrlgenToml.py enforces a limit on the maximum radius for alkali atoms, to avoid the linear-dependency problem between APWs and MTOs.

  • When we treat molecules (especially dimers), we have to use very small size of MT radius. T.Kotani checked PMT works well even for such systems. However, we need examination a little more.

lmf: Solve one-body problem.

This is for band calculation in LDA/GGA and LDA+U. In addition, we can add the potential term for QSGW via sigm.<sname>.

Example:

mpirun -np 4 lmf si [options] > llmf

This is a case with ctrlg.si.toml.

options

  • quit option at some point. --quit=band, --quit=ldau... We need to do 'grep cmdopt SRC//.f90|grep quit' to know details.
  • --tdos total dos calculation. But we usually use `job_tdos'
  • --ctrlg:<dotted.path>=<value> : Runtime override of a key in ctrlg.<sname>.toml. The path uses dotted TOML syntax (e.g. --ctrlg:bz.nkabc=[8,8,8], --ctrlg:ham.scaledsigma=0.8, --ctrlg:ham.phispinsym=true, --ctrlg:verbose=50, --ctrlg:spec.1.r=2.5 for the 1st [[spec]]). Substituted into the in-memory TOML before parsing; the file on disk is untouched. Each applied override is logged on rank 0. Older syntaxes (-vfoo=val, -v[<path>]=val, --[<path>]=val, --toml.<path>=val, --pr=N, --time=N,M, --phispinsym) abort with a one-line migration hint.

We have some kinds of options for electron density plot, boltztrap and so on. (not yet described).

Input files

(<sname> is the positional argument of lmf, e.g. si for lmf si reading ctrlg.si.toml.)

  • syml.<sname> symmetry line for band plot (usually job_band calls lmf internally)
  • sigm.<sname> a part of QSGW calculation
  • atmpnu.{1,2,3}.<sname> generated by lmfa (when [ham] readp = true)

Output files

  • rst.<sname> restart file, containing density and related information. Together with ctrlg.<sname>.toml, atmpnu*, sigm*, and rst* we can resume an lmf calculation. (dmat* is used for LDA+U.)

  • save.<sname> Minimal iteration history for lmf / lmfa / lmchk, with total energies for each lmf SCF step.

  • __mix.<sname> mixing file for electron density. When you stop iteration at the middle, you may need to delete this. mixm retains prior iterations of sets of input and output moments. Used by the Anderson or Broyden mixing scheme to accelerate convergence towards self-consistency. Usually you should delete these when starting a new calculation (such as changing the lattice constant) so it doesn't get used in subsequent runs.

** Main Source** : SRC/main/lmf.f90

ctrlg.<sname>.toml — current input format (2026-05+)

lmf, lmfa, lmchk read TOML only since 2026-05. The single file ctrlg.<sname>.toml carries everything that used to live in ctrl.<sname> plus the GW driver and product-basis sections that used to live in GWinput. Per-atom product-basis tables (sname-free) sit in a sibling PB.<sname>.toml. Run Legacy2toml.py <sname> inside any old working directory to generate both files.

PB.<sname>.toml is for the GW path (consumed by hbasfp0 / hvccfp0 / etc. when generating the mixed product basis). It is auto-emitted by ctrlgenToml.py (or Legacy2toml.py) and does not normally need hand editing — when you tune a calculation, edits go into ctrlg.<sname>.toml.

File structure (sections)

toml
# Top-level scalars
symgrp  = "find"        # space-group spec: 'find' = auto-detect
verbose = 35            # console verbosity
time    = [0, 0]        # CPU timing log: [depth, on-the-fly]

[struc]   alat / plat                              (nspec / nbas auto-derived from arrays)
[[site]]  atom / pos / xpos / af / relax           (one table per atom)
[[spec]]  atom / z / r / rsmh / eh / lmx / ...     (one table per species)
[bz]      nkabc / metal / tetra / npts / ...
[iter]    nit / mix / b / conv / convc / umix / tolu
[ham]     nspin / rel / so / phispinsym / xcfun / gmax / pwmode / pwemax / oveps / ...
[gw]      n1n2n3 / QpGcut_psi / HistBin_dw / iSigMode / niw / esmr / GaussSmear / ...
[product_basis]   pb_tolerance / pb_lcutmx
[blocks]  QPNT, QforEPS, Worb (multi-line strings, GW-side blocks)

Worked example: bcc-Cu (FCC, 1 atom, non-magnetic)

The full ctrlg.cu.toml from Samples/EPS/EPS_Cu/ is shown below. Inline # comments document each key's role; copy-paste the file as a starting point for FCC monatomic metals and adjust [spec], [bz], [ham] to your case.

toml
# Top-level scalars
symgrp  = "find"  # 'find' = auto-detect space group from lattice + species
verbose = 35      # 31 default, 35 verbose, 41+ debug
time    = [0, 0]  # CPU timing log: [depth, on-the-fly]

[struc]
alat  = 6.798     # lattice constant (a.u.)
plat  = [[0.0, 0.5, 0.5],   # primitive vectors in units of alat
         [0.5, 0.0, 0.5],
         [0.5, 0.5, 0.0]]

[[site]]
atom = "Cu"
pos  = [0.0, 0.0, 0.0]

[[spec]]
atom   = "Cu"
z      = 29
r      = 2.33    # MT radius (a.u.)
rsmh   = [1.17, 1.17, 1.17, 1.17]   # smoothing radii per l
eh     = [-1.0, -1.0, -1.0, -1.0]   # tail energies
rsmh2  = [1.17, 1.17, 1.17]         # second basis group
eh2    = [-2.0, -2.0, -2.0]
lmx    = 3       # basis l-cutoff
lmxa   = 4       # augmentation l-cutoff
nmcore = 1       # 1: spin-averaged core; 0: spin-polarized core
kmxa   = 5       # radial expansion order at tail sites

[bz]
nkabc  = [12, 12, 12]   # k-mesh divisions; 1 entry => isotropic
metal  = 3              # 0 insulator, 3 tetra+broadening (safe metal)
savdos = true           # write dos.tot.* file
npts   = 2001
dosmax = 1.5

[iter]
nit   = 30        # max self-consistency iterations
mix   = "A2"      # B3 = Broyden hist=3 (default); A2 = Anderson hist=2
conv  = 1e-05     # max dE between iterations (Ry)
convc = 1e-05     # max d(rho_out - rho_in) (Ry)
b     = 0.2       # mixing ratio

[ham]
nspin       = 1   # 1 nonmag, 2 spin-polarized (then spec.mmom seeds)
rel         = true
so          = 0   # 0 none, 1 L.S, 2 Lz.Sz
gmax        = 12.0   # real-space mesh G-cutoff (Ry); alt: ftmesh
frzwf       = false
xcfun       = 1   # 1=VWN, 2=Barth-Hedin, 103=PBE-GGA
forces      = 0
scaledsigma = 1.0   # QSGW mixing: 1.0 full, 0.8 = QSGW80
oveps       = 0.0
pwmode      = 1   # 0=MTO 1=PMT 2=APW 11=PMT(|q+G|, default) 12=LAPW
pwemax      = 3.0  # APW cutoff (Ry)

# === GW driver (used by lmf --jobgw=N and gwsc) ===
[gw]
n1n2n3        = [10, 10, 10]   # GW BZ mesh (typically smaller than [bz].nkabc)
QpGcut_psi    = 3.0     # |q+G| cutoff for eigenfunctions
QpGcut_cou    = 2.0     # |q+G| cutoff for Coulomb / W
unit_2pioa    = false   # false: a.u.;  true: 2*pi/alat
HistBin_dw    = 1e-05   # bin width on real-axis at omega=0
HistBin_ratio = 1.03
iSigMode      = 3       # self-energy mode (3 = standard QSGW)
niw           = 10      # # of imag-axis frequencies
delta         = -1e-06
deltaw        = 0.02
esmr          = 0.003   # hsfp0 smearing
GaussSmear    = true

[product_basis]
pb_tolerance = [0.001]  # drop near-linear-dep products (default 1e-3)
pb_lcutmx    = [4]      # max l-cutoff per atom

# Per-atom product-basis tables (nlx / valence / core) live in PB.<sname>.toml.

# === GW additional blocks (legacy GWinput tags become multi-line strings) ===
[blocks]
QforEPS = """
 0 0 0.00050
 0 0 0.00100
 0 0 0.00200
"""

Worb = """
!  1 Cu   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
"""

That's the entire input. [blocks] carries the legacy <...>...</...> GWinput tag content as multi-line TOML strings; the body is parsed opaquely (per-block) by the GW driver.

Per-physics deltas (from the Cu starting point)

  • Spin-polarized metal (Fe, Ni, FeCo): set [ham].nspin = 2 and add mmom = [0, 0, 2.5] (or per-l guess) to each [[spec]].
  • SOC (HAM_SO): set [ham].so = 1 (full L·S) or 2 (Lz·Sz only), with [ham].nspin = 2. See Samples/MLOsamples/FeSoc/.
  • Insulator / semiconductor (Si, GaAs): [bz].metal = 0 and [bz].tetra = true; smaller [bz].nkabc; [ham].pwemax ~3 is enough.
  • LDA+U: add idu = [0, 0, 2, 2], uh = [0, 0, 0.1, 0.632], jh = [0, 0, 0, 0.055] to [[spec]]. dmatu.<sname> is read separately if present.
  • Atomic-position relaxation: [dyn].mode = 4 (CG) or 6 (Broyden), set [[site]].relax = [1, 1, 1] per atom.
  • GW BZ mesh: keep [gw].n1n2n3[bz].nkabc (often 1/2 or 2/3 of it) — n1n2n3 dominates GW wall-time.

Run-time -v overrides

The legacy -v<NAME>=<VAL> (where <NAME> was a %const symbol baked into ctrl.<sname>) is replaced by bracketed dotted-path syntax processed in-memory by m_toml_override.f90:

bash
# OLD (legacy ctrl + %const)
lmf si -vnk=8 -vmetal=3 -vnspin=2 -vso=0

# NEW (ctrlg.toml + path syntax)
lmf si --ctrlg:bz.nkabc=[8,8,8] --ctrlg:bz.metal=3 --ctrlg:ham.nspin=2 --ctrlg:ham.so=0

The bracketed key is the dotted TOML path ([section.key] or [section.subkey]); the right-hand side parses as TOML ([8,8,8] for an integer vector, 1 for an int, 1.0 for a float, "r4z r3d r2x" for a string). No on-disk rewrite of the .toml file takes place.

Legacy ctrl.<sname> ↔ TOML path map

Most legacy Category_Token keys map 1:1 onto [section.key] after lower-casing. A few are renamed or restructured:

legacy Category_TokenTOML locationnote
STRUC_ALAT / STRUC_PLAT[struc].alat / .plat
SITE_ATOM=, POS=, XPOS=[[site]] atom = ...; pos = [...] (or xpos)one [[site]] table per atom
SPEC_ATOM=, Z=, R=, RSMH=, EH=, ...[[spec]] atom = ...; z = ...; r = ...; rsmh = [...]one [[spec]] table per species; R/W= and R/A= kept as "r/a" quoted-key
BZ_NKABC / BZ_METAL / BZ_TETRA[bz].nkabc / .metal / .tetra
HAM_NSPIN / HAM_SO / HAM_XCFUN / HAM_GMAX / HAM_PWMODE / HAM_PWEMAX[ham].nspin etc.
HAM_FORCES / HAM_OVEPS / HAM_FRZWF / HAM_REL[ham].forces etc.
HAM_ScaledSigma[ham].scaledsigmalowercase
HAM_READP / HAM_PNUFIX / HAM_V0FIX[ham].readp etc.
ITER_NIT / ITER_MIX / ITER_CONV / ITER_CONVC / ITER_UMIX / ITER_TOLU[iter].nit / .mix / ...
SYMGRP / SYMGRPAFtop-level symgrp = "..." (and symgrp_af)not nested in a section
EWALD_TOL[ewald].tolrarely touched
DYN_MODE / DYN_NIT / DYN_HESS / ...[dyn].mode etc.
IO_VERBOS / IO_TIMtop-level verbose / timepromoted out of [io] (section dropped)
<Worb>...</Worb> block[blocks].Worb = """ ... """multi-line string
<QforEPS>...</QforEPS> block[blocks].QforEPS = """ ... """
n1n2n3 (GWinput)[gw].n1n2n3 = [k1,k2,k3]int vector
HistBin_dw / HistBin_ratio / niw / delta / esmr / GaussSmear (GWinput)[gw].HistBin_dw etc.unchanged names, lowercased
product-basis cut-offs (tolerance, lcutmx from <PRODUCT_BASIS>)[product_basis].pb_tolerance / .pb_lcutmx
product-basis per-atom tables (nlx, valence, core)PB.<sname>.toml (separate file)per-sname

The full schema lives in SRC/exec/ctrl_schema.py (the conversion source of truth). Annotations / inline comments are applied by SRC/exec/toml_comments.py.


LDA+U (TOML)

LDA+U is selected per species by writing the idu, uh, jh vectors into each [[spec]] table. Indices [s, p, d, f]:

toml
[[spec]]
atom = "Er"
z    = 68
r    = 3.00
# ... rsmh, eh, ... ...
idu  = [0, 0, 2, 2]          # 0 = none, 1 = AMF, 2 = FLL.  +10 disables when sigm.* exists
uh   = [0.0, 0.0, 0.10, 0.632]    # Hubbard U (Ry)
jh   = [0.0, 0.0, 0.00, 0.055]    # exchange J (Ry)

Mode codes (idu[l]):

  • 0 — no U on this l-channel
  • 1AMF (Around-Mean-Field), Petukhov, PRB 67, 153106 (2003)
  • 2FLL (Fully Localized Limit), Liechtenstein, PRB 52, R5467 (1995)
  • 12 / 21 / ... — same code +10 means "skip LDA+U when sigm.<sname> exists" (so a QSGW run with sigm falls back to plain QSGW).

dmatu.<sname> (density matrix) is read & written automatically — it is the LDA+U analogue of rst.<sname>. A first-shot LDA run without U populates it. You can override the initial occupation by hand-writing occnum.<sname> (one line of 2l+1 numbers per spin) — see the legacy LDA+U notes for the ErAs example and the spin-configuration hazard.

Mixing of the dmat happens independently of the charge with linear mixing:

toml
[iter]
umix = 0.2          # dmat mixing beta (0..1)
tolu = 0.0          # rms tol where dmat mixing stops (0 = always mix)

Check the dmat once with lmf <sname> --quit=dmat — it stops after the initial setup and prints the matrix without writing any restart files.

Core hole (TOML)

Partial core-hole occupancy implements Slater transition-state ideas (useful for XAS / unbinding 4f). Set per species:

toml
[[spec]]
atom    = "Nd"
z       = 60
r       = 3.00
p       = [0.0, 0.0, 0.0, 5.2]    # treat 4f as core, 5f as valence
c_hole  = "4f"                     # core channel to perturb
c_hq    = [-11.0]                  # excess electron charge in that channel
# c_hq    = [-7.0, 7.0]            # optional 2nd entry = spin moment

Charge bookkeeping:

Q(spin1) = full_core_count + c_hq[1]/2 + c_hq[2]/2
Q(spin2) = full_core_count + c_hq[1]/2 - c_hq[2]/2

Negative c_hq[1] removes electrons (a hole); the optional c_hq[2] polarises the core (used e.g. for the Gd 4f trick — c_hq = [-7, 7] freezes 7-up / 0-down in the 4f core while 5f remains valence).

Confirm neutrality with lmfa <sname> | grep -i 'add core hole'. See the legacy core-hole walkthrough for the full Gd / Nd / CrN case study.

Local orbitals (TOML)

The local-orbital channel pz is the analog of the continuously-variable principal quantum number p. Both are per-species, per-l vectors in [[spec]]:

toml
[[spec]]
atom = "Ga"
# p[0..3] = s,p,d,f valence principal quantum numbers (continuous);
#          fractional part 0.5 = mid-band, ->0 = bottom, ->1 = top.
p   = [0.0, 0.0, 4.0, 0.0]       # 4d "valence-like"
# pz[0..3] = semicore (lower n) or high-lying (higher n) local-orbital prinq;
#           fractional part ~0.9 = semicore, ~0.3 = high-lying.
pz  = [0.0, 0.0, 3.9, 0.0]       # 3d treated as semicore local orbital
# add 10 to pz[l] to attach a smooth-Hankel tail (extended local orbital).

Notes:

  • Integer part of pzp controls the principal quantum number used for the radial function (semicore → int(pz) = int(p) − 1, high-lying → int(pz) = int(p) + 1).
  • Fractional part: 0.9 for semicore, 0.3 for high-lying is the common choice; smaller fractional ⇒ lower linearization energy.
  • pz[l] + 10 (i.e. write pz = [0, 0, 13.9, 0]) attaches a smooth-Hankel tail (extended local orbital). Use this when the deep state spills into the interstitial.
  • Verify the configuration with lmfa <sname> | grep -i conf — the line shows which states are treated as core / valence / lo.

Common pitfalls:

  • Conventional (non-extended) local orbitals on semicore states rely on the valence envelope for representation outside the MT sphere — keep at least one rsmh for that l small (~1) with eh rather negative (~-1).
  • Extended-lo matching can fail ("mtchre: failed to match phi'/phi") when the fractional part of pz is too close to 1.0 — reduce it (e.g. 0.98 → 0.85).
  • The p with the higher principal quantum number is automatically frozen — only the deepest state is allowed to float (controlled by idmod).

See the legacy local-orbital notes for the historical sm-Hankel mtchre discussion.

SYMGRP / symgrp — space-group specification

In TOML the space-group spec is the top-level symgrp string:

toml
symgrp     = "find"           # auto-detect from lattice + species (default)
symgrp_af  = "R4z*I"          # extra generator for AF symmetry (optional)

symgrp either takes the literal string "find" (auto-detect) or a space-separated list of generators. The generators are the same as the legacy SYMGRP token:

  • R<n>X, R<n>Y, R<n>Z, R<n>Dn-fold rotation around X, Y, Z, (1,1,1).
  • M<axis> — mirror.
  • I — inversion.
  • <axis> = X | Y | Z | D | (nx,ny,nz) — pick a Cartesian axis or an explicit direction.
  • Products with *, e.g. I*R4X.
  • Translations: r6z:(0,0,0.4778973) (Cartesian) or r6z::(0,0,1/3) (fractional, multiples of plat).

Example (cubic):

toml
symgrp = "R4X MX R3D"        # 4-fold around X, mirror in X, 3-fold around (1,1,1) ⇒ 48 symops

Mix-and-find:

toml
symgrp = "R4X find"          # force 4-fold around X then let lmf find the rest

Disable symmetry entirely:

toml
symgrp = "e"

lmchk prints the recognised symops at the top of its console output — use it to verify the symmetry was parsed as intended. The inversion is implicit in the DFT path when the potential is local; pay attention to the inversion-related notes in the console banner.

Q: Should the Harris-Foulkes and Hohenberg-Kohn Sham functionals agree at self-consistency?

(due to Mark van Schilfgaarde) A: Yes. If they do not, either you have not reached self-consistency, or a tolerance is set too loosely in the evaluation of the matrix elements. A likely culprit is that the mesh of points for the interstitial integrals is not fine enough. Here is part of an output where mesh of 14x14x14 divisions were used for the interstitial density.

 GVLIST: gmax = 4.702 a.u. created 973 vectors of 2744 (35%)
         mesh has 14 x 14 x 14 divisions; length 0.588, 0.588, 0.668
 SGVSYM: 170 symmetry stars found for 973 reciprocal lattice vectors
...

 sugcut:  make orbital-dependent reciprocal vector cutoffs for tol= 1.00E-05
 spec      l    rsm    eh     gmax    last term    cutoff
  Te       0*   1.30  -0.10   5.220    9.30E-05     973*
  Te       1*   1.30  -0.10   5.597    4.36E-04     973*
  Te       2    1.30  -0.10   5.976    2.04E-03     973*
  Te       0*   1.40  -1.00   4.847    2.11E-05     973*
  Te       1    1.40  -1.00   5.182    9.90E-05     973*
  E        0*   1.50  -0.30   4.524    1.06E-05     847
  E        1    1.50  -0.30   4.823    2.01E-05     973*

The table reflects how well each of the basis orbitals is converged in a PW expansion, which is used to make matrix elements of the interstitial potential. Only the E s orbital is converged below the specified tolerance (10-5 ). Convergence in the Te d orbital is particularly poor; however, the Te d is only minimally part of the bonding, and its poor convergence doesn't affect the energy much. In this case (3 Te atoms), the HF and HK total energies differ by ~10-4 Ry. Below is a table showing the convergence in HF energy as a function of the number of divisions, and also the difference between HK and HF energies.

  n       ehf         ehf-ehk
  14 -14561.140624    0.000089
  15 -14561.133966    0.000017
  16 -14561.132309    0.000005
  20 -14561.131170    0.000000

Legacy reference

The bulk of historical Category_Token reference, old physics-notes (APW test, sm-Hankel mtchre discussion, old SPEC notes, old tetrahedron memo) has been moved to a dedicated page:

That page is the canonical place to look up the meaning of a legacy key, then translate to TOML via the Legacy ↔ TOML map above.