mag4.energy_mapping

Energy-mapping (linear least-squares) configuration generator.

Layer: common — an alternative to the four-state method for extracting Heisenberg J from DFT total energies. Where the four-state method targets a handful of uu/dd/ud/du configurations per bond, energy-mapping enumerates every symmetry-/coefficient-inequivalent collinear order of a given (super)cell and later fits

E(config) = E0 + Σ_k J_k · c_k(config)

by a single linear least-squares solve over all configurations (see mag4-extract --method energy-mapping, Phase 3).

This module produces, for one (super)cell, the list of inequivalent orders and their integer coupling coefficients c_k (the design-matrix rows). The ±1 Ising enumeration and the coefficient counting mirror the standalone ising_magnetic.py precursor, re-expressed on mag4’s CrystalData.

Module Attributes

DEFAULT_MAX_ATOMS

Above this magnetic-atom count the 2^N enumeration is rejected outright (overridable per call).

Functions

build_unique_groups(records)

Wrap each record as a one-member group for the VASP/WIEN2k writers.

config_energy_coefficients(atoms, lat_mat, ...)

Coupling coefficients of each spin order's energy.

count_ring(plaquettes, spin_map)

Ring coefficient = Σ s_i s_j s_k s_l over the (4×-redundant) squares, divided by 4.

detect_report_method(report_path)

Return the Method: tag of a mag4 report (four-state if absent).

enumerate_orders(crystal, couplings[, tol, ...])

Enumerate the inequivalent collinear magnetic orders of crystal.

parse_energy_mapping_report(report_path)

Parse the design-matrix report written by write_energy_mapping_report().

select_ring_plaquettes(couplings, ...[, ...])

Pick the coupling shell that forms the square lattice for the ring term.

write_energy_mapping_report(path, records, ...)

Write the design-matrix report consumed by mag4-extract.

mag4.energy_mapping.DEFAULT_MAX_ATOMS = 20

Above this magnetic-atom count the 2^N enumeration is rejected outright (overridable per call). 2^20 ≈ 1e6 orders is already minutes of work.

mag4.energy_mapping.config_energy_coefficients(atoms, lat_mat, couplings, spin_vectors, *, tol=0.0005, distmax=None)[source]

Coupling coefficients of each spin order’s energy.

For every spin vector (±1 per magnetic atom, in atoms order) returns ({Jname: c_k}, |Sz|) with c_k = Σ_{⟨ij⟩∈k} s_i s_j summed over the unique bonds of shell k in the cell — i.e. the design-matrix row, so that E[config] = E0 + Σ_k c_k · (J_k · S²). This is what lets one verify that a four-state combination isolates a single J (the other couplings’ coefficients cancel). Bonds are counted once via the same cell↔image folding as _coefficients().

Return type:

List[Tuple[Dict[str, int], int]]

Parameters:
mag4.energy_mapping.count_ring(plaquettes, spin_map)[source]

Ring coefficient = Σ s_i s_j s_k s_l over the (4×-redundant) squares, divided by 4.

Return type:

int

Parameters:
mag4.energy_mapping.select_ring_plaquettes(couplings, cell_atoms, image_atoms, prefer_label=None, prefer_dist=None, tol_pos=0.15)[source]

Pick the coupling shell that forms the square lattice for the ring term.

The shortest M–M distance is not necessarily the square edge (e.g. SrFeO₂’s shortest Fe–Fe is a linear c-axis contact that forms no square). If the user pins a shell (prefer_label / prefer_dist) it is used; otherwise every shell is tried from shortest to longest and the first that closes into squares is returned. Returns (plaquettes, n_unique, n_folded, dist) or (None, 0, 0, None).

Parameters:
mag4.energy_mapping.enumerate_orders(crystal, couplings, tol=0.0005, distmax=None, *, max_atoms=20, ring=False, ring_coupling=None, ring_dist=None, ring_tol=0.15)[source]

Enumerate the inequivalent collinear magnetic orders of crystal.

Every 2^N ±1 assignment over the N magnetic atoms is grouped by its coupling-coefficient signature (c_1, …, c_n, |Sz|); configurations sharing a signature are energy-degenerate in the model, so one representative ordering is kept per signature.

With ring=True a four-spin cyclic (ring) exchange coefficient is also computed per order and a "Jring" column appended (see select_ring_plaquettes()); the square-lattice shell is auto-detected unless pinned with ring_coupling / ring_dist.

Returns (records, labels, ring_distance) where labels are the coupling names in column order ("Jring" last when present), ring_distance is the square edge length (or None), and each record is:

{"number": int,            # 1-based, deterministic
 "coefficients": {name: c},
 "sz": int,                # |Sz| of the order
 "degeneracy": int,        # how many ±1 orders share this signature
 "spin_vector": [±1, …]}   # representative, in target_species order
Raises:

ValueError – When N exceeds max_atoms (the 2^N enumeration would be intractable) — use a smaller supercell or raise max_atoms.

Return type:

Tuple[List[dict], List[str], Optional[float]]

Parameters:
mag4.energy_mapping.build_unique_groups(records)[source]

Wrap each record as a one-member group for the VASP/WIEN2k writers.

mag4.vasp.build_magmom_lines() / mag4.vasp.create_config_dirs() consume List[List[FourStateConfig]] and read only spin_vector (for the MAGMOM) plus coupling_name / state_label (for the printed label). Energy-mapping has no per-bond label, so the coefficient signature is used for display.

Return type:

List[List[FourStateConfig]]

Parameters:

records (List[dict])

mag4.energy_mapping.write_energy_mapping_report(path, records, labels, couplings, supercell, name, *, tr_pairs=None, config_msgs=None)[source]

Write the design-matrix report consumed by mag4-extract.

The format is deliberately simple and machine-parseable: a Method: tag, the coupling labels + distances, then one whitespace-separated row per configuration giving config<N>, degeneracy, Sz and the integer coefficient of each coupling (column order = labels).

tr_pairs (from --check-degeneracy) adds one pair: configA == configB line per time-reversal-degenerate pair; mag4-extract reads them back and reports |ΔE| per pair. config_msgs (magnetic Shubnikov groups) are recorded as comment lines — informational, ignored by parsers.

Return type:

None

Parameters:
mag4.energy_mapping.detect_report_method(report_path)[source]

Return the Method: tag of a mag4 report (four-state if absent).

Legacy four-state reports carry no Method: line, so their absence is treated as four-state.

Return type:

str

Parameters:

report_path (str)

mag4.energy_mapping.parse_energy_mapping_report(report_path)[source]

Parse the design-matrix report written by write_energy_mapping_report().

Returns {"method", "labels", "dist_of", "supercell", "records"} where each record is {"number", "degeneracy", "sz", "coefficients": {label: c}}.

Return type:

dict

Parameters:

report_path (str)