mag4.extract

J-value extraction from a completed four-state DFT campaign.

Pipeline (mirrors what the user did manually before this module existed):

  1. Parse the four_state_report.dat written by mag4.cli.fourstate.main() to recover, for each shell Jₙ, which 4 unique configurations contribute to the formula JS² = (E_uu + E_dd E_ud E_du) / 4.

  2. Read each configuration’s converged DFT total energy from configN/ via mag4.energy.get_energy().

  3. Combine energies with the formulas to produce JS² (and J if a spin S is given).

This module is the pure-Python core; the CLI in mag4.cli.extract adds argument parsing, pretty-printing and j_values.dat output.

Module Attributes

DEFAULT_REPORT_NAME

Name of the report file produced by mag4-magnetic (default).

Functions

compute_j_values(formulas, energies[, spin, ...])

Apply each formula to the matching energies and return the J table.

parse_report_config_cells(report_path)

Read per-config n_atoms values from a four_state_report.dat.

parse_report_config_sz(report_path)

{config_index: Sz} from the per-config Spins: lines, where Sz = Σ s_i of the ±1 spin vector (the net collinear moment quantum number of that configuration).

parse_report_formulas(report_path)

Extract every J = ( E[#…] + …) / 4 line from a report file.

parse_report_supercell(report_path)

Read the supercell multipliers (na, nb, nc) from a four-state report header line Supercell : na×nb×nc.

parse_report_supercell_atoms(report_path)

Read the total atom count in the supercell from a four_state_report.dat header.

parse_report_tr_pairs(report_path)

[(configA, configB), …] from the TIME-REVERSAL DEGENERACY CHECK section written by mag4-magnetic --check-degeneracy (any method).

read_all_energies(compound_dir, code[, ...])

Walk <compound_dir>/configN/ and run the energy parser on each.

read_struct_atom_counts(compound_dir, n_configs)

For every configN/ directory under compound_dir, sum the MULT= fields of configN.struct (whatever WIEN2k's init_lapw left on disk after possibly accepting sgroup's rewrite) and return {config_index atom_count}.

read_wien2k_struct_atom_count(struct_path)

Sum the MULT=N fields across a WIEN2k case.struct file.

write_j_values_dat(results, path, ...[, ...])

Persist the four-state results to a fixed-width text file.

Classes

Formula(name, distance_A[, config_uu, ...])

One row of the EXTRACTION FORMULAS section.

JResult(name, distance_A, formula[, ...])

One row of the final J table emitted by compute_j_values().

mag4.extract.DEFAULT_REPORT_NAME = 'four_state_report.dat'

Name of the report file produced by mag4-magnetic (default).

class mag4.extract.Formula(name, distance_A, config_uu=None, config_dd=None, config_ud=None, config_du=None, incomplete=False, divisor=4, raw='')[source]

Bases: object

One row of the EXTRACTION FORMULAS section.

Parameters:
  • name (str)

  • distance_A (float)

  • config_uu (int | None)

  • config_dd (int | None)

  • config_ud (int | None)

  • config_du (int | None)

  • incomplete (bool)

  • divisor (int)

  • raw (str)

name

Coupling label as printed in the report, e.g. "J1".

Type:

str

distance_A

Mean M–M distance of the shell in Å.

Type:

float

config_uu, config_dd, config_ud, config_du

Unique-configuration indices (1-based, matching the configN/ directory names) whose energies are combined as (E_uu + E_dd E_ud E_du) / 4.

Type:

int

incomplete

True when the report flagged this shell as INCOMPLETE (cell too small to give a distinct dimer). In that case the four config indices are unset and J cannot be computed.

Type:

bool

raw

Original text of the line, kept for traceability.

Type:

str

name: str
distance_A: float
config_uu: int | None = None
config_dd: int | None = None
config_ud: int | None = None
config_du: int | None = None
incomplete: bool = False
divisor: int = 4
raw: str = ''
property config_indices: List[int]

Return the four config indices in (uu, dd, ud, du) order.

mag4.extract.parse_report_formulas(report_path)[source]

Extract every J = ( E[#…] + …) / 4 line from a report file.

Parameters:

report_path (str) – Path to a four_state_report.dat produced by mag4-magnetic.

Returns:

One entry per coupling shell discovered in the report, in the order they appear. Shells flagged INCOMPLETE in the report are included with incomplete=True (so the caller can warn about them) but with no config indices.

Return type:

list of Formula

Raises:
  • FileNotFoundError – If report_path doesn’t exist.

  • ValueError – If the file exists but contains no recognisable formula or INCOMPLETE line — most likely the wrong file was passed.

mag4.extract.parse_report_config_cells(report_path)[source]

Read per-config n_atoms values from a four_state_report.dat.

The report emits a Cell: a=… | | n_atoms=N | line under each Config #uid: block when WIEN2k cell reduction is on. Returns {config_index n_atoms}. Older reports without the line yield an empty dict and the caller falls back to assuming every config sits in the same cell (today’s behaviour, no rescaling).

Return type:

Dict[int, int]

Parameters:

report_path (str)

mag4.extract.read_wien2k_struct_atom_count(struct_path)[source]

Sum the MULT=N fields across a WIEN2k case.struct file.

This is the authoritative atom count WIEN2k’s :ENE refers to. Whenever init_lapw’s sgroup rewrites the struct (cell reduction, lattice-letter correction), mag4’s pre-emption from four_state_report.dat can disagree – the post-sgroup file on disk is the truth. Returns None if the file is missing or no MULT= field could be parsed.

Example: a P6_3/mmc primitive cell with 2 Cr + 2 Sb listed (each MULT=2) returns 4.

Return type:

Optional[int]

Parameters:

struct_path (str)

mag4.extract.read_struct_atom_counts(compound_dir, n_configs)[source]

For every configN/ directory under compound_dir, sum the MULT= fields of configN.struct (whatever WIEN2k’s init_lapw left on disk after possibly accepting sgroup’s rewrite) and return {config_index atom_count}.

Missing struct files or unparseable ones are simply skipped – callers should fall back on the report’s recorded counts.

Return type:

Dict[int, int]

Parameters:
  • compound_dir (str)

  • n_configs (int)

mag4.extract.parse_report_supercell_atoms(report_path)[source]

Read the total atom count in the supercell from a four_state_report.dat header.

The four-state formula is defined on the supercell mag4 built (e.g. NiO 1×1×2 → 16 atoms). When configs are computed in reduced cells (Fm-3m conv → 2 atoms, etc.), their WIEN2k :ENE values must be scaled up to the supercell size before applying the formula. This helper returns the integer that mag4-extract should use as the scaling target.

Returns None for reports written by mag4 versions before the Total atoms in supercell line was added; the caller then falls back to math.lcm(per-config n_atoms).

Return type:

Optional[int]

Parameters:

report_path (str)

mag4.extract.parse_report_supercell(report_path)[source]

Read the supercell multipliers (na, nb, nc) from a four-state report header line Supercell : na×nb×nc. None if absent.

Return type:

Optional[Tuple[int, int, int]]

Parameters:

report_path (str)

mag4.extract.parse_report_config_sz(report_path)[source]

{config_index: Sz} from the per-config Spins: lines, where Sz = Σ s_i of the ±1 spin vector (the net collinear moment quantum number of that configuration).

Return type:

Dict[int, int]

Parameters:

report_path (str)

mag4.extract.parse_report_tr_pairs(report_path)[source]

[(configA, configB), …] from the TIME-REVERSAL DEGENERACY CHECK section written by mag4-magnetic --check-degeneracy (any method).

Each pair is related only by an antiunitary operation (unitary crystal op × time reversal), so the two DFT energies must coincide; the caller reports |ΔE| per pair. Empty when the report has no such section.

Return type:

List[Tuple[int, int]]

Parameters:

report_path (str)

class mag4.extract.JResult(name, distance_A, formula, energies_eV=<factory>, JS2_eV=None, JS2_meV=None, J_meV=None, J_K=None, error=None)[source]

Bases: object

One row of the final J table emitted by compute_j_values().

Parameters:
name

Coupling label ("J1" …).

Type:

str

distance_A

Mean M–M distance of the shell, Å.

Type:

float

formula

The original parsed formula (provides config indices, raw text).

Type:

Formula

energies_eV

Per-state total energies in eV. Keys: "uu", "dd", "ud", "du". None when the corresponding config did not converge (or didn’t exist).

Type:

dict[str, float or None]

JS2_eV, JS2_meV

Computed JS² = (E_uu + E_dd E_ud E_du) / 4. None if the formula could not be evaluated (any energy missing).

Type:

float or None

J_meV, J_K

Computed J = JS² / in meV and Kelvin (J / k_B). Only populated when a positive spin S was passed.

Type:

float or None

error

Human-readable reason if JS2_eV is None (which configs failed, INCOMPLETE shell, …).

Type:

str or None

name: str
distance_A: float
formula: Formula
energies_eV: Dict[str, float | None]
JS2_eV: float | None = None
JS2_meV: float | None = None
J_meV: float | None = None
J_K: float | None = None
error: str | None = None
property computed: bool

True iff JS² could be computed (all 4 energies present).

mag4.extract.compute_j_values(formulas, energies, spin=None, config_n_atoms=None, n_supercell_atoms=None)[source]

Apply each formula to the matching energies and return the J table.

Parameters:
  • formulas (list of Formula) – Output of parse_report_formulas().

  • energies (dict[int, EnergyResult]) – Map config_index EnergyResult for every config the formulas reference. Indices come from the configN/ dir name, 1-based. Configs that didn’t converge MUST still be present with EnergyResult.converged = False so this function can attribute the failure correctly.

  • spin (float, optional) – Magnetic spin quantum number S. When given (>0), each JS² is divided by to also report J in meV and in Kelvin.

  • config_n_atoms (dict[int, int], optional) – Map config_index n_atoms from parse_report_config_cells(). When supplied, each contributing config’s total energy is rescaled by N_LCM / N_X before applying the four-state formula — necessary when mag4-magnetic wrote each config in its own primitive cell (--reduce-cell, the default). When omitted every config is assumed to sit in the same cell (legacy behaviour, no rescaling).

  • n_supercell_atoms (int | None)

Returns:

One entry per input formula, same order.

Return type:

list of JResult

mag4.extract.read_all_energies(compound_dir, code, max_index=None, scf_basename=None)[source]

Walk <compound_dir>/configN/ and run the energy parser on each.

Parameters:
  • compound_dir (str) – Root directory containing the configN/ subdirectories.

  • code ({'vasp', 'wien2k'}) – Forwarded to mag4.energy.get_energy().

  • max_index (int, optional) – If given, only configs config1configN are read. Useful to short-circuit on very large compound dirs.

  • scf_basename (str | None)

Returns:

Map config_index EnergyResult. Empty if no configN/ directory was found.

Return type:

dict[int, EnergyResult]

mag4.extract.write_j_values_dat(results, path, compound_dir, code, spin=None, supercell=None, energies=None, config_sz=None, mags=None)[source]

Persist the four-state results to a fixed-width text file.

Beyond the J table this records the supercell used and a per-configuration block (total energy, SCF iterations, converged moment vs the configuration’s Sz) so the file is self-contained — everything shown on screen, plus the moment/Sz consistency check.

# mag4-extract — four-state J values # compound: <dir> code: vasp spin: 3.5 # supercell: 1x1x2 # # Per-configuration energies # config iter energy (eV) Sz mag exp|mag| status # … # # name d_mean(A) JS2(eV) JS2(meV) J(meV) J(K) status J1 3.8987 -0.12345678 -123.456789 -10.082 -116.99 OK

Return type:

None

Parameters: