mag4.wien2k

WIEN2k input generation: configN.inst + configN.struct per four-state spin configuration.

Layer: WIEN2k-specific (one of the two DFT back-ends; see also vasp.py).

In each configN/ directory mag4 writes:

  • POSCAR – same VASP file used by --code vasp (kept for cross-checking; also accepted as input by WIEN2k’s xyz2struct).

  • configN.inst – produced by piping the u/d/n spin pattern into WIEN2k’s instgen -ask script. Named after the directory so the case == basename(pwd) convention works out of the box.

  • configN.struct – written directly by Python (no xyz2struct needed). Every atom is emitted as inequivalent (MULT=1) with a unique label of the form <element><n> ("Cs1", "V 9", "I17" …) so WIEN2k cannot merge atoms via symmetry analysis. Only the identity symmetry op is written. This guarantees the atom order in configN.struct matches the order assumed by configN.inst.

Mapping convention

Each entry of the spin pattern maps as follows:

+1 (or any positive  value)  →  ``u``
-1 (or any negative  value)  →  ``d``
 0 (non-magnetic atom)       →  ``n``

So a MAGMOM line -7 2*7 -7 3*7 4*0 becomes d u u d u u u n n n n.

Module Attributes

ANG_TO_BOHR

Ångström → Bohr conversion factor used by WIEN2k struct files.

SYMMORPHIC_SG_NUMBERS

The 73 symmorphic space groups (no glide planes / no screw axes).

Functions

analyze_config_magnetic_group(crystal, group, *)

Magnetic space group (Shubnikov/BNS) of a spin-decorated configuration.

analyze_config_symmetry(crystal, group, *[, ...])

Run spglib on the spin-decorated configuration and pack the result.

build_udn_lines(unique_groups, crystal[, ...])

Per-unique-config list of u/d/n letters in POSCAR order.

find_instgen()

Locate the WIEN2k instgen script.

magmom_to_udn(values)

Translate a flat list of MAGMOM values to the u/d/n letters.

run_instgen(udn_letters, crystal, instgen_path)

Run instgen -ask once and return the produced case.inst text.

wien2k_label(element_symbol, idx)

Format an atom label per WIEN2k case.struct convention.

write_case_inst_files(unique_groups, ...[, ...])

For every unique configuration, write a configN.inst file in configN/.

write_case_struct_files(crystal, n_configs, ...)

Write configN.struct into every configN/ subdirectory.

write_job_scripts(parent_dir, *[, ...])

Write job.init and job.run into parent_dir and chmod +x them.

write_struct_file(crystal, path, *[, title, ...])

Write a complete WIEN2k case.struct from a CrystalData.

write_struct_file_symmetric(crystal, ...[, ...])

Write a WIEN2k case.struct that exposes the configuration's detected space-group symmetry.

write_stub_struct(crystal, path)

Write a minimal case.struct good enough for instgen.

write_symmetric_case_files(unique_groups, ...)

Write configN.struct and configN.inst per config with a shared, symmetry-derived atom order.

Classes

ConfigSymmetry(spacegroup_number, ...[, ...])

Symmetry analysis of a single spin-decorated configuration.

MagneticGroupInfo(uni_number, bns_number, ...)

Magnetic (Shubnikov) space group of one spin-decorated configuration.

mag4.wien2k.ANG_TO_BOHR: float = 1.8897261339212517

Ångström → Bohr conversion factor used by WIEN2k struct files.

mag4.wien2k.SYMMORPHIC_SG_NUMBERS: frozenset = frozenset({1, 2, 3, 5, 6, 8, 10, 12, 16, 21, 22, 23, 25, 35, 38, 42, 44, 47, 65, 69, 71, 75, 79, 81, 82, 83, 87, 89, 97, 99, 107, 111, 115, 119, 121, 123, 139, 143, 146, 147, 148, 149, 150, 155, 156, 157, 160, 162, 164, 166, 168, 174, 175, 177, 183, 187, 189, 191, 195, 196, 197, 200, 202, 204, 207, 209, 211, 215, 216, 217, 221, 225, 229})

The 73 symmorphic space groups (no glide planes / no screw axes). Used by the --no-reduce branch in write_symmetric_case_files() to decide whether to refine orbit groupings (_cell_compatible_symmetry + _relabel_…) or to fall back to “every atom MULT=1” (_ungrouped_symmetry).

For symmorphic parents, the refined point group at origin is closed under composition modulo the supercell lattice, so the union-find in _cell_compatible_symmetry produces correct supercell-as-P-Bravais orbits. For non-symmorphic parents the parent’s intrinsic glide / screw translations alias with supercell-induced internal translations and the union-find over-merges (e.g. MULT=16 in a Pmna 2×2×1 supercell where Pmna’s max Wyckoff multiplicity is 8).

mag4.wien2k.magmom_to_udn(values)[source]

Translate a flat list of MAGMOM values to the u/d/n letters.

Parameters:

values (sequence of float) – One value per atom in POSCAR order. Sign carries the spin direction; zero means non-magnetic.

Returns:

One letter per atom: "u" for positive, "d" for negative, "n" for zero.

Return type:

list of str

Examples

>>> magmom_to_udn([-7, 7, 7, -7, 7, 7, 7, 0, 0, 0, 0])
['d', 'u', 'u', 'd', 'u', 'u', 'u', 'n', 'n', 'n', 'n']
mag4.wien2k.build_udn_lines(unique_groups, crystal, spin_magnitude=1.0)[source]

Per-unique-config list of u/d/n letters in POSCAR order.

Returns a list of length len(unique_groups); each element is the list of u/d/n letters for one configuration. Order matches mag4.vasp.build_magmom_lines().

Return type:

List[List[str]]

Parameters:
mag4.wien2k.wien2k_label(element_symbol, idx)[source]

Format an atom label per WIEN2k case.struct convention.

  • Two-letter element: e.g. "Cs1" → cols 1-2 = "Cs".

  • One-letter element: "V 1" (letter + space) → cols 1-2 = "V ".

The convention matters because instgen reads the element from the first two characters of each RMT= line in case.struct.

Return type:

str

Parameters:
  • element_symbol (str)

  • idx (int)

mag4.wien2k.write_stub_struct(crystal, path)[source]

Write a minimal case.struct good enough for instgen.

Only the per-atom RMT= line is emitted (one per atom in POSCAR order) because that is the only thing instgen parses. Use write_struct_file() to produce a full, ready-to-use struct file.

Return type:

None

Parameters:
class mag4.wien2k.ConfigSymmetry(spacegroup_number, spacegroup_symbol, rotations, translations, origin_shift, new_to_old, orbits, frac_coords_new, mapping_to_primitive=<factory>)[source]

Bases: object

Symmetry analysis of a single spin-decorated configuration.

The cell is kept verbatim from the input CrystalData; only the atom ordering (within the cell) and the symmetry-op list are derived.

Parameters:
spacegroup_number, spacegroup_symbol

Space group reported by spglib for the spin-decorated structure.

rotations, translations

Symmetry operations in the input cell basis, ready to be written verbatim into a WIEN2k struct file (rotations is integer; the translations are in fractional coordinates).

origin_shift

Origin shift that spglib would apply to put the structure into the standard setting. Kept for diagnostics; not applied to atom positions here — we keep input positions so the rotations/translations in the input basis act directly.

new_to_old

new_to_old[i] is the original POSCAR index of the atom that now sits at position i in the symmetrised order. Length = number of atoms.

orbits

List of Wyckoff orbits in the new order: each orbit is a list of consecutive new-order indices that share a symmetry equivalent class. len(orbits) is the number of inequivalent sites (== WIEN2k’s NEQUIV).

frac_coords_new

Fractional coordinates in the new order (shape (n_atoms, 3)).

spacegroup_number: int
spacegroup_symbol: str
rotations: ndarray
translations: ndarray
origin_shift: ndarray
new_to_old: List[int]
orbits: List[List[int]]
frac_coords_new: ndarray
mapping_to_primitive: List[int]

For each atom in the new order, the index of the corresponding atom in spglib’s primitive cell. Used by the WIEN2k struct writer to fold orbits by lattice-centering equivalence (only one rep per primitive index is emitted under an F/B/C-centred letter, matching WIEN2k’s “list one of four / one of two” convention).

property n_atoms: int
property n_inequiv: int
class mag4.wien2k.MagneticGroupInfo(uni_number, bns_number, og_number, msg_type, parent_number, parent_symbol, n_unitary, n_primed, mpg_symbol='', mpg_kind='')[source]

Bases: object

Magnetic (Shubnikov) space group of one spin-decorated configuration.

spglib classifies the configuration (collinear moments included, so the PRIMED operations — unitary op × time reversal — are counted) into one of the 1651 magnetic space-group types. spglib provides the standard numbers but not the symbol string; the BNS number is the citable label (symbol lookup: Bilbao MGENPOS / ISO-MAG).

msg_type is the Shubnikov type: 1 = colorless (no primed ops), 2 = grey (contains pure time reversal — only for zero-moment structures), 3 = black-white (half the point operations primed), 4 = black-white with anti-translations (a translation × T maps the sublattices).

Parameters:
  • uni_number (int)

  • bns_number (str)

  • og_number (str)

  • msg_type (int)

  • parent_number (int)

  • parent_symbol (str)

  • n_unitary (int)

  • n_primed (int)

  • mpg_symbol (str)

  • mpg_kind (str)

uni_number: int
bns_number: str
og_number: str
msg_type: int
parent_number: int
parent_symbol: str
n_unitary: int
n_primed: int
mpg_symbol: str = ''
mpg_kind: str = ''
property type_roman: str
short()[source]

Compact display string, e.g. BNS 65.490 (type IV, parent Cmmm).

Return type:

str

point_group()[source]

Magnetic point group with its kind, e.g. mmm1' (grey).

Dropping the translations from the magnetic space group gives the magnetic point group exactly: an anti-translation (type IV) becomes pure time reversal 1’, so the point group is GREY G1'; a type-III group keeps half its point operations primed and is written in the Shubnikov G(H) notation (parent, unitary subgroup); a type-I group is the ordinary (colourless) symbol.

Return type:

str

mag4.wien2k.analyze_config_magnetic_group(crystal, group, *, spin_magnitude=1.0, symprec=0.001)[source]

Magnetic space group (Shubnikov/BNS) of a spin-decorated configuration.

Unlike analyze_config_symmetry() — which colours up/down spins as different species and therefore sees only the UNITARY part of the magnetic group — this passes the collinear moments to spglib’s magnetic dataset, so operations combined with time reversal (primed) are included. Returns None when spglib is too old (< 2.0) or fails; callers should then simply omit the magnetic-group line.

Return type:

Optional[MagneticGroupInfo]

Parameters:
mag4.wien2k.analyze_config_symmetry(crystal, group, *, spin_magnitude=1.0, symprec=0.001)[source]

Run spglib on the spin-decorated configuration and pack the result.

Atoms in CrystalData are coloured according to their spin (see _spglib_atom_types()), so the detected space group is the magnetic space group of the configuration projected onto the user’s cell — equivalent to “highest symmetry compatible with this cell”.

The returned ConfigSymmetry carries:

  • the rotations/translations in the input cell basis (so we can write them straight into a WIEN2k struct file);

  • the permutation that groups atoms by their Wyckoff orbit, with orbits ordered by the index of their representative — this becomes the new atom order on disk.

On any spglib error or empty dataset we fall back to a P1 (identity-only) ConfigSymmetry so the rest of the pipeline can proceed unchanged.

Return type:

ConfigSymmetry

Parameters:
mag4.wien2k.write_struct_file(crystal, path, *, title=None, rmt=2.0, npt=781, r0=None, calc_mode='RELA', lattice=None)[source]

Write a complete WIEN2k case.struct from a CrystalData.

Every atom is emitted as a separate inequivalent site (MULT=1) with a unique label of the form <element><n> ("Cs1", "V 9", "I17" …). Only the identity symmetry operation is written, so WIEN2k will not merge or reorder atoms. This guarantees that the atom order in configN.struct matches the order assumed by configN.inst.

See write_struct_file_symmetric() for the spin-aware variant that uses real-space symmetry (default in the CLI; this function is kept as a fallback behind --no-symmetrize-struct).

Parameters:
  • crystal (CrystalData) – The (super-)cell as produced by mag4.supercell.

  • path (str) – Where to write the struct file (full path including filename).

  • title (Optional[str]) – Free-text title written on line 1. Defaults to a mag4-tagged note.

  • rmt (Union[float, Dict[str, float]]) – Muffin-tin radius in bohr. Either a single value applied to every element (default 2.0) or a dict {element_symbol: value}.

  • npt (int) – Number of radial mesh points (default 781; must be odd).

  • r0 (Union[float, Dict[str, float], None]) – First radial mesh point in bohr. None (default) → picked per-Z via _default_r0(); a single float applies to all elements; a dict allows per-element overrides.

  • calc_mode (str) – "RELA" (relativistic, default) or "NREL" (non-relativistic).

  • lattice (Optional[str]) – WIEN2k single-letter lattice code. Auto-detected from the cell angles when None.

Return type:

None

Notes

The per-atom header line follows the format declared in the WIEN2k user guide: (A10, 5X, I5, 5X, F10.8, 5X, F10.5, 5X, F10.5) for name, NPT, R0, RMT, Z respectively. The 5X gaps carry decorative text (" NPT=", "  R0=", " RMT=", "   Z:") for readability — WIEN2k skips them when parsing.

mag4.wien2k.write_struct_file_symmetric(crystal, config_sym, path, *, title=None, rmt=2.0, npt=781, r0=None, calc_mode='RELA', lattice=None, labels=None)[source]

Write a WIEN2k case.struct that exposes the configuration’s detected space-group symmetry.

One inequivalent block is emitted per Wyckoff orbit (MULT = orbit size), with the orbit’s representative listed on the leading ATOM line and the remaining members on continuation lines between the MULT= line and the per-orbit NPT/R0/RMT line. Each orbit gets a unique <element><n> label so WIEN2k cannot merge orbits that happen to share an element. The trailing symmetry block lists every rotation/translation reported by spglib in the input cell basis.

Atom positions are written in the order encoded by config_sym.frac_coords_new — i.e. spglib’s equivalence classes grouped together, with orbits ordered by their representative index.

Return type:

None

Parameters:
mag4.wien2k.write_case_struct_files(crystal, n_configs, parent_dir, *, rmt=2.0, npt=781, r0=None)[source]

Write configN.struct into every configN/ subdirectory.

The cell and atom list are identical across configurations; only the spin pattern (in configN.inst) differs. We therefore write the same struct content N times, naming each file after its directory.

Return type:

List[str]

Parameters:
mag4.wien2k.write_symmetric_case_files(unique_groups, crystal, parent_dir, *, instgen_path=None, spin_magnitude=1.0, symprec=0.001, rmt=2.0, npt=781, r0=None, reduce_cell=False)[source]

Write configN.struct and configN.inst per config with a shared, symmetry-derived atom order.

For each configuration:

  1. Run analyze_config_symmetry() once on the spin-decorated cell.

  2. Write configN.struct via write_struct_file_symmetric() — one block per Wyckoff orbit, full symmetry-op tail, unique per-orbit labels.

  3. Drive instgen with one u/d/n answer per orbit (the spin of the orbit’s representative) and save the resulting configN.inst.

Because both files are produced from the same ConfigSymmetry, their atom orders are guaranteed to agree without any post hoc reordering.

Returns a dict with four keys: "struct" (list of struct paths), "inst" (list of inst paths), "sym" (list of ConfigSymmetry results, one per config — handy for tests), and "crystals" (the per-config reduced CrystalData used to write each struct — used by the report writer to record per-config cell metadata for mag4-extract’s cell-size rescaling).

When reduce_cell is true (--reduce; the default is off, so every config keeps the one working supercell and shares identical numerics) each config is rewritten in its colored-structure primitive cell via mag4.geometry.reduce_to_primitive() — multiplicities then match the parent SG’s standard Wyckoff table, and downstream DFT runs are correspondingly cheaper for high-symmetry configs.

Return type:

Dict[str, List]

Parameters:
mag4.wien2k.write_job_scripts(parent_dir, *, functional=None, kspacing=None, element=None, ldaul=None, ldauu=None, ldauj=None)[source]

Write job.init and job.run into parent_dir and chmod +x them.

Both scripts iterate over the sibling config*/ directories via foreach; they belong at the compound level, not inside each configN/. Existing files are overwritten so re-running mag4-magnetic is safe. The template follows P. Blaha’s recommended workflow: setrmt (so the muffin-tin radii mag4 writes into the struct files are placeholders), init_lapw -sp -prec 2n -noreduc -nohdlo -nokshift (-nokshift is always present, so the k-mesh is unshifted by default), and an interactive check when sgroup proposes an origin-shifted struct (accept only if lattice type and atom count are unchanged — sgroup may e.g. reduce P to CXY, which would silently change the cell the report’s energy formulas refer to).

kspacing (Å⁻¹, VASP convention; defaults to mag4’s 0.3) is converted to bohr⁻¹ and inserted as init_lapw -numk -1 <spacing> so the WIEN2k k-mesh matches the VASP one. When functional == "PBE+U" and ldauu is given, the init_orb -orb heredoc is generated active with <element> <l> <U> <J> from element/ldaul/ldauu/ldauj, and job.run calls runsp with -orb; otherwise the block stays commented out as a template.

ldauu/ldauj are taken in eV (VASP convention — the very same values the INCAR’s LDAUU/LDAUJ receive) and divided by RY_TO_EV on the way out, because init_orb reads U and J in Rydberg. ldaul is a quantum number and is passed through unchanged. A comment above the heredoc echoes both the eV input and the Ry output so the conversion is checkable in the generated script.

Return type:

List[str]

Parameters:
  • parent_dir (str)

  • functional (str | None)

  • kspacing (float | None)

  • element (str | None)

  • ldaul (int | None)

  • ldauu (float | None)

  • ldauj (float | None)

mag4.wien2k.find_instgen()[source]

Locate the WIEN2k instgen script.

Lookup order:

  1. $WIEN2k_INSTGEN environment variable, if set.

  2. instgen on $PATH.

  3. instgen_lapw on $PATH (the canonical WIEN2k name).

  4. $WIENROOT/instgen_lapw.

  5. ~/bin/instgen.

Returns the absolute path or None if not found.

Return type:

Optional[str]

mag4.wien2k.run_instgen(udn_letters, crystal, instgen_path)[source]

Run instgen -ask once and return the produced case.inst text.

Internally uses a temporary directory containing a stub case.struct, pipes the u/d/n letters as answers, runs instgen, reads back the resulting case.inst and cleans up.

Raises:

RuntimeError – If instgen exits non-zero or fails to produce case.inst.

Return type:

str

Parameters:
mag4.wien2k.write_case_inst_files(unique_groups, crystal, parent_dir, instgen_path=None, spin_magnitude=1.0)[source]

For every unique configuration, write a configN.inst file in configN/.

The output file is named after the directory (config1.inst inside config1/, etc.) so that WIEN2k’s standard case == basename(pwd) convention works directly on the user’s HPC machine.

Parameters:
Returns:

Paths of the written configN.inst files, in config order.

Return type:

list of str