crystod.mag#
Public magnetism API of CrystOD: the crystod-mag domain.
This module covers the symmetry analysis of spin arrangements. The spins on
the sites of one element are treated as axial-vector degrees of freedom, the
3N-dimensional spin space is decomposed into irreps of the space group at a q
point, and the resulting symmetry-adapted spin bases (cluster multipoles /
symmetry-adapted multipole moments, SAMM, after M.-T. Suzuki et al., Phys.
Rev. B 95, 094406 (2017) and Phys. Rev. B 99, 174407 (2019)) are classified
as ferromagnetic (cluster dipole) or antiferromagnetic (octupole and higher).
It mirrors the crystod-mag command, whose spin listings, VESTA exports and
noncollinear magnetization input (VASP MAGMOM, Quantum ESPRESSO
starting_magnetization/angle1/angle2) are built from these
functions; the implementation lives in crystod.spin_basis.
Spin representation (crystod-mag --qpoint, and the survey over all
special k points when --qpoint is omitted)
get_spin_representation: the little-group irreps at q and the axial-vector representation on the selected sites, ready forspgrep.representation.project_to_irrep.
Multipole classification (crystod-mag at q = 0)
get_multipole_rank_lists: for every irrep, the ranks of the magnetic multipoles (dipole, octupole, …) in which it appears.separate_ferro_combination: splits the net-moment combination (FM, cluster dipole) off the projected spaces of one irrep; the rest are AFM.MULTIPOLE_NAMES: rank-to-name table (1: "dipole",3: "octupole", …).
A session mirrors the command:
from phonopy.interface.vasp import read_vasp
from spgrep.representation import project_to_irrep
from crystod import mag, phonon
vib = phonon.SymmetryOnlyVibrations(read_vasp("POSCAR"), standardize=False)
sites = [i for i, s in enumerate(vib.primitive_cell.symbols) if s == "Ni"]
q = [0, 0, 0]
irreps, spin_rep, mapping = mag.get_spin_representation(vib, sites, q)
labels = vib.get_irrep_labels(q, irreps, mapping)
ranks = mag.get_multipole_rank_lists(vib, vib.rotations[mapping], irreps)
for irrep, label, rank_list in zip(irreps, labels, ranks):
spaces = [s.real for s in project_to_irrep(spin_rep, irrep)]
if spaces:
ferro, afm = mag.separate_ferro_combination(spaces, spin_rep, len(sites))
Attributes resolve lazily (PEP 562): importing this module is instant, and
phonopy/spgrep are loaded on the first attribute access. Bad input raises
ValueError here, where the implementation module raises SystemExit.
- crystod.mag.get_multipole_rank_lists(vibrations, little_rotations, irreps, max_rank=9)[source]#
Ranks at which each irrep occurs in the magnetic multipole representations.
crystod-maguses these lists at q = 0 to name the symmetry-adapted spin bases: the spaces of an irrep are named in the order of the ranks in its list, so the ferromagnetic combination (cluster dipole, rank 1) comes first and the antiferromagnetic ones follow as octupole, … (the logic of Table III of M.-T. Suzuki et al., Phys. Rev. B 95, 094406). The rank-pmagnetic (time-odd, axial) multipole transforms as the angular-momentum-prepresentation with parity(-1)**(p + 1)under inversion: the dipole (p = 1) and octupole (p = 3) are parity-even, the magnetic quadrupole (p = 2) is parity-odd, and so on. The multiplicity of every irrep is obtained by character orthogonality against the rotation characterssin((p + 1/2) theta) / sin(theta / 2)of the proper part of every little-group operation.- Parameters:
vibrations (SymmetryOnlyVibrations) – Symmetry container of the primitive cell (
crystod.phonon.SymmetryOnlyVibrations); its lattice converts the integer rotations to Cartesian form.little_rotations (ndarray[tuple[Any, ...], dtype[int64]]) – Integer rotation matrices of the little-group operations, in the order of the irrep matrices: normally
vibrations.rotations[mapping]with themappingreturned byget_spin_representation.irreps – The spgrep irreps of the little group, as returned by
get_spin_representation.max_rank (int) – Highest rank
pincluded in the search.
- Returns:
One list per irrep (same order as
irreps), holding the ranks1 <= p <= max_rankat which the irrep appears in the rank-pmagnetic multipole representation, in increasing order and repeated according to the multiplicity.MULTIPOLE_NAMEStranslates ranks to names.- Return type:
list[list[int]]
Example
>>> # vib, sites, q: see get_spin_representation (O sites of SrTiO3) >>> irreps, spin_rep, mapping = mag.get_spin_representation(vib, sites, q) >>> labels = vib.get_irrep_labels(q, irreps, mapping) >>> rotations = vib.rotations[mapping] >>> ranks = mag.get_multipole_rank_lists(vib, rotations, irreps) >>> dict(zip(labels, ranks))["GM4+(3)"] [1, 3, 5, 5, 7, 7, 9, 9, 9]
- crystod.mag.get_spin_representation(vibrations, site_indices, qpoint)[source]#
Irreps and the axial-vector (spin) representation on selected sites at q.
This is the first step of
crystod-mag(at the--qpointgiven, or at every special k point in survey mode): the spins of thesite_indicesatoms of the primitive cell are treated as axial vectors, and the little group ofqpointacts on the 3N-dimensional spin space by the same construction as the vibration (polar-vector) representation ofcrystod-phonon, with the Cartesian rotationRreplaced bydet(R) * Rand the site permutation restricted to the selected sites. The Bloch-phase convention is that of spgrep, so the returned matrices can be projected onto the returned irreps directly withspgrep.representation.project_to_irrep.- Parameters:
vibrations (SymmetryOnlyVibrations) – Symmetry container of the primitive cell (
crystod.phonon.SymmetryOnlyVibrations); itsrotations,translationsandprimitive_celldefine the space group.site_indices (list[int]) – Indices (into
vibrations.primitive_cell) of the N atoms that carry a spin, e.g. every atom of the magnetic element.qpoint (list[float]) – The q point in primitive reciprocal coordinates, e.g.
[0, 0, 0]or[0.5, 0.5, 0.5].
- Returns:
(irreps, spin_rep, mapping).irrepsis the list of spgrep irreps of the little group atqpoint(each an array of shape(order, dim, dim));spin_repis the complex array of shape(order, 3N, 3N)holding the spin-representation matrix of every little-group operation, in the order of the irrep matrices;mappingis the integer array that indexes those operations invibrations.rotations(whatget_irrep_labelsandget_multipole_rank_listsexpect).- Return type:
tuple
Example
>>> from phonopy.interface.vasp import read_vasp >>> from crystod import mag, phonon >>> from crystod.examples import example_path >>> cell = read_vasp(example_path("221_PPOSCAR_SrTiO3")) >>> vib = phonon.SymmetryOnlyVibrations(cell, standardize=False) >>> symbols = vib.primitive_cell.symbols >>> sites = [i for i, s in enumerate(symbols) if s == "O"] # 3 sites >>> q = [0, 0, 0] >>> irreps, spin_rep, mapping = mag.get_spin_representation(vib, sites, q) >>> spin_rep.shape (48, 9, 9) >>> vib.get_irrep_labels(q, irreps, mapping)[6] 'GM4+(3)'
- crystod.mag.separate_ferro_combination(spaces, representation, n_sites)[source]#
Split the ferromagnetic combination off the spaces of one irrep.
At q = 0 an irrep can occur several times in the spin representation (
2 x GM4+for the three Ni sites of AlNi3);crystod-magcalls this function once per irrep label with all of its projected spaces. The spaces are first aligned to a common partner basis (an intertwiner withrepresentationis found for every space, and complex circular bases are recombined into real ones), then the net momentssum_i S_iof the aligned spaces are combined into one unit vector: its unitary completion gives the unique combination that carries a net moment (the cluster dipole, printed asFM) and the orthogonal combinations withsum_i S_i = 0(AFM: octupoles and higher). When no space carries a net moment, or the completion does not separate cleanly, the aligned spaces are returned unchanged as antiferromagnetic.- Parameters:
spaces (list[ndarray[tuple[Any, ...], dtype[float64]]]) – Real basis arrays of shape
(dim, 3N)(one row per partner of the irrep;3N= three Cartesian components of N spins) that all carry the same irrep, e.g. the output ofspgrep.representation.project_to_irrepfor one irrep.representation (ndarray[tuple[Any, ...], dtype[complex128]]) – The spin-representation matrices of shape
(order, 3N, 3N)returned byget_spin_representation; used to align the spaces to a common basis.n_sites (int) – The number N of spin-carrying sites.
- Returns:
(ferro, afm).ferrois the basis array of shape(dim, 3N)with a net moment (Nonewhen no combination has one) andafmis the list of the remaining net-zero basis arrays; together they span the same space as the input.- Return type:
tuple
Example
>>> # spin_rep, irreps, sites: see get_spin_representation (SrTiO3, O) >>> import numpy as np >>> from spgrep.representation import project_to_irrep >>> gm4p = irreps[6] # GM4+, twice >>> spaces = [np.real(s) for s in project_to_irrep(spin_rep, gm4p)] >>> ferro, afm = mag.separate_ferro_combination(spaces, spin_rep, 3) >>> ferro.shape, len(afm) ((3, 9), 1) >>> bool(np.abs(afm[0].reshape(3, 3, 3).sum(axis=1)).max() < 1e-8) True
- crystod.mag.MULTIPOLE_NAMES = {0: 'monopole', 1: 'dipole', 2: 'quadrupole', 3: 'octupole', 4: 'hexadecapole', 5: '32pole', 6: '64pole'}#
Names of the magnetic multipole ranks used in the
crystod-magoutput (rankp->2**p-pole):{1: "dipole", 3: "octupole", ...}.