Input Keys Reference

Magesty.jl reads structure and interaction settings from a TOML file (consumed by SCEBasis(toml_path) / SCEBasis(input_dict)). Fit parameters (estimator, regularization, torque weight) are not part of the TOML — they are passed in Julia at fit time, e.g. fit(SCEFit, dataset, Ridge(lambda = 1e-4)).

Annotated Example

[general]
name = "bccfe"
kd   = ["Fe"]           # list of element names
nat  = 16               # total number of atoms in the supercell
periodicity = [true, true, true]  # apply periodic boundary to all (x, y, z) directions

[symmetry]
tolerance = 1e-5        # symmetry detection tolerance (optional, default 1e-3)
isotropy = true         # restrict to Lf = 0 (isotropic exchange) terms

[interaction]
nbody = 2               # maximum interaction body
[interaction.body1]
lmax.Fe = 0             # 1-body maximum angular momentum per element, i.e. this represents on-site anisotropy
[interaction.body2]
lsum = 2                # cutoff summation of l values for basis functions
cutoff."Fe-Fe" = -1     # pairwise cutoff radius in Å (-1 uses all possible pairs)

[structure]
kd_list  = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]  # element index per atom
lattice  = [            # lattice parameters
  [5.66, 0.0, 0.0],
  [0.0, 5.66, 0.0],
  [0.0, 0.0, 5.66],
]
position = [            # fractional coordinates
  [0.00, 0.00, 0.00],
  [0.25, 0.25, 0.25],
  [0.00, 0.00, 0.50],
  [0.50, 0.00, 0.00],
  [0.00, 0.50, 0.00],
  [0.25, 0.25, 0.75],
  [0.75, 0.25, 0.25],
  [0.25, 0.75, 0.25],
  [0.00, 0.50, 0.50],
  [0.50, 0.00, 0.50],
  [0.50, 0.50, 0.00],
  [0.25, 0.75, 0.75],
  [0.75, 0.25, 0.75],
  [0.75, 0.75, 0.25],
  [0.50, 0.50, 0.50],
  [0.75, 0.75, 0.75],
]

Key Reference

[general]

KeyTypeRequiredDescription
nameStringyesSystem name
kdVector{String}yesElement names
natIntyesNumber of atoms in supercell
periodicityVector{Bool}noPeriodic boundary conditions (default: [true,true,true])

[symmetry]

KeyTypeRequiredDescription
toleranceFloat64noSymmetry detection tolerance (default: 1e-3)
isotropyBoolnoOnly include isotropic (Lf = 0) terms (default: false)

tolerance is the spglib symprec: the Cartesian distance (in Å) below which two positions count as coincident during the symmetry search. Coordinates coming out of a structural relaxation typically carry residual distortions of order 1e-4 Å, which a tight tolerance reads as a genuine symmetry breaking. The detected space group and the tolerance it was obtained with are both printed in the SYMMETRY block of the log; check them against the symmetry you expect, because a demoted space group leaves equivalent sites independent and silently inflates the number of SCE coefficients. When a tolerance ten times looser would find more symmetry operations, a warning reports both results.

[interaction]

KeyTypeRequiredDescription
nbodyIntyesMaximum interaction order
body1.lmax.<elem>IntnoOn-site max angular momentum per element (wildcard * accepted, see below)
body<n>.lsumIntyes (n≥2)Max L sum for n-body basis
body<n>.cutoff."<e1>-<e2>"Float64yes (n≥2)Pairwise cutoff radius in Å (-1 = include all pairs; wildcards accepted, see below)

Wildcard species notation

For body1.lmax.<species> and body<n>.cutoff."<e1>-<e2>" the species name may be replaced with *, matching every species. When several keys cover the same species or pair, the most specific key wins (it is not the textual order of the keys). For pair keys the specificity order is:

TierPatternExample
0 (most specific)both concrete"Co-Ni"
1one wildcard"Fe-*", "*-Fe"
2 (least specific)both wildcards"*-*"

Pair keys are unordered: "Co-Ni" and "Ni-Co" are equivalent (the parser rejects them as duplicates if both are supplied). The species notation for body1.lmax has only two tiers: concrete species ("Fe") wins over the wildcard ("*").

If two keys at the same tier cover the same pair with different values (for instance "Fe-*" and "*-Ni" both covering Fe-Ni), the parser reports an ambiguity and requires the user to add a tier-0 entry for that pair. Unknown species names in a non-wildcard key are an error.

[interaction]
nbody = 2

[interaction.body1.lmax]
"*"  = 2          # default for every species
"Fe" = 4          # Fe overrides the default

[interaction.body2]
lsum = 4

[interaction.body2.cutoff]
"*-*"  = 8.0      # default for every pair
"Fe-*" = 10.0     # every pair involving Fe (incl. Fe-Fe)
"Co-Ni" = 12.0    # tier-0 entry — wins over any wildcard match

Interaction cluster definition

Given the cutoff table for body n, an n-body atom set is accepted as an interaction cluster if every one of its C(n, 2) pairwise cartesian distances is less than or equal to the corresponding pair-specific cutoff body<n>.cutoff."<kᵢ>-<kⱼ>". The same rule applies uniformly to every n ≥ 2: pair, triplet, quartet, and so on. No body order treats the criterion differently.

Concretely, for body n and an n-body candidate (a₁, …, aₙ) of species (k₁, …, kₙ):

the candidate is accepted iff ‖xᵢ − xⱼ‖ ≤ body<n>.cutoff."<kᵢ>-<kⱼ>" for every pair (i, j) with 1 ≤ i < j ≤ n.

If even one pair distance exceeds its cutoff the candidate is rejected in full, regardless of how many other pairs fit. Setting a pair cutoff to -1 disables the constraint for that pair only — the rule is still evaluated for every other pair in the cluster.

Supercell size and representable interaction range

Pair distances are evaluated under the minimum-image convention: each pair is assigned to its shortest periodic image across the supercell. A displacement is represented uniquely only when it is the strictly shortest vector among its periodic images — that is, when it lies inside the Wigner–Seitz cell of the supercell lattice. An interaction whose range exceeds that region cannot be represented: its shortest image folds onto a closer lattice vector, so the model treats it as zero.

A convenient, direction-independent guarantee is range < L/2, where L is the shortest supercell edge (the inscribed-sphere radius of the cell): any interaction shorter than this is always representable. The exact bound is anisotropic, though. For a cubic supercell of edge L the representable range reaches L/2 along ⟨100⟩ but √3·L/2 along ⟨111⟩ — e.g. in a bcc 2×2×2 cell (L = 2a) the origin–body-corner pair at distance √3·a = √3·L/2 sits on the Wigner–Seitz corner and is still represented. Choose the supercell so that every interaction you intend to fit lies inside this region; taking range < L/2 is the safe rule.

A related subtlety affects pairs lying exactly on a Wigner–Seitz face: they lose their odd folded-angular-momentum (Lf) couplings, including the Dzyaloshinskii–Moriya term. See Symmetry adaptation for the minimum-image geometry and this cancellation.

[structure]

KeyTypeRequiredDescription
kd_listVector{Int}yesElement index (1-based, into kd) per atom
lattice3×3 Float64yesLattice vectors in Å; each of the three rows in the TOML array defines one lattice vector (a₁, a₂, a₃)
positionVector of 3-vectorsyesFractional atomic coordinates

Fit parameters

The TOML covers the material — structure, symmetry, interaction. The fit — estimator, regularization, torque weight, training data path — is configured in Julia at fit time. The training data path is also passed in Julia (to SCEDataset), not in the TOML.

basis   = SCEBasis("input.toml")
dataset = SCEDataset(basis, "EMBSET")
f = fit(
    SCEFit, dataset,
    Ridge(lambda = 1e-4);   # estimator: OLS() or Ridge(; lambda)
    torque_weight = 1.0,    # ∈ [0, 1]: 0 = energy only, 1 = torque only,
                            # 0.5 = balanced (per-sample MSE convex combination)
)
  • torque_weight[0, 1] — the convex weight applied to the per-sample torque MSE; the energy MSE gets 1 - torque_weight. 0 = fit energies only; 1 = fit torques only. Default: 1.0 (torque-only fit; the SCE coefficients are best determined by torque residuals, and j0 is recovered in closed form from the energy block).
  • EstimatorOLS() for no regularization, or Ridge(lambda = λ) for L2 with strength λ ≥ 0. ElasticNet, Lasso, AdaptiveLasso, AdaptiveRidge, and PrecomputedPilot are also available; see the API Reference for the full estimator list. The reference energy j0 is recovered analytically after the solve (closed-form mean(y_E - X_E * jphi)) and is therefore not subject to any estimator's penalty.