pyspinw

pySpinW: Spin Hamiltonian calculations in Python

SpinW is a Python library that can plot and numerically simulate magnetic structures and excitations

class LatticeSite(pyspinw.serialisation.SPWSerialisable):

A spin site within a lattice

Parameters
  • i,j,k - required Fractional coordinates within unit cell
  • sx, sy, sz - Spin components in the Cartesian directions defined by x||a, z perpendicular to a-b
  • supercell_spins - Spin for each propagation vector
  • g - g-tensor (3x3)
  • name
LatticeSite( i: float, j: float, k: float, sx: float | None = None, sy: float | None = None, sz: float | None = None, supercell_spins: ArrayLike | None = None, g: ArrayLike | None = None, name: str = '')
serialisation_name = 'site'
def n_components(self):

Number of spin components for this site

unique_id

Unique ID for this site

name

Name given to this site

i

Fractional position along first unit cell axis

j

Fractional position along second unit cell axis

k

Fractional position along third unit cell axis

ijk

ijk values as a numpy array

base_spin

spins as numpy array

spin_data

Get all the spin data

g: numpy.ndarray

Magnetic g-factor, a 3x3 matrix/tensor

values

ijk and spins as a numpy 6-vector

parent_site

Get the parent site (just itself for non-implied sites)

@staticmethod
def from_coordinates(coordinates: numpy.ndarray, name: str = ''):

Create from an array of values

class Anisotropy(pyspinw.serialisation.SPWSerialisable):

Defines the anisotropy at a given site

@check_sizes(anisotropy_matrix=(3, 3))
Anisotropy(site: LatticeSite, anisotropy_matrix: ArrayLike)
serialisation_name = 'anisotropy'
scalar_parameters = []
unique_id

Unique ID for this anisotropy

site

Get the site for this anisotropy

anisotropy_matrix: numpy.ndarray

Matrix specifying the anisotropy - A term in the Hamiltonian

parameter_string

A string representation of the parameters

def updated( self, site: LatticeSite | None = None, anisotropy_matrix: ArrayLike | None = None):

Return a copy of this anisotropy term with variables replaced

class AxisMagnitudeAnisotropy(pyspinw.Anisotropy):

Anisotropy oriented with axes, but variable amount in x, y and z

@check_sizes(direction=(3,), force_numpy=True)
AxisMagnitudeAnisotropy( site: LatticeSite, a: float, direction: ArrayLike = array([0, 0, 1]))
scalar_parameters = ['a']
a

Amount of anisotropy (anisotropy constant)

constant

Amount of anisotropy (anisotropy constant), alias for a

direction

The principal direction of the anisotropy

parameter_string

A string representation of the parameters

def updated( self, site: LatticeSite | None = None, a: float | None = None, direction: ArrayLike | None = None):

Return a copy of this anisotropy term with variables replaced

class HeisenbergExchange(pyspinw.exchange.Exchange):

Heisenberg Exchange, which takes the form

H_ij = J_ij (S_i . S_j)

Parameters
  • site_1: Identifier for S_i
  • site_2: Identifier for S_j
  • j: The exchange coefficient
HeisenbergExchange( site_1: LatticeSite, site_2: LatticeSite, j: float, cell_offset: pyspinw.cell_offsets.CellOffset | tuple[int, int, int] | None = None, name: str = '')
exchange_type = 'Heisenberg'
parameters = ['j']
parameter_defaults = [1.0]
short_string = 'J'
j

Exchange constant

def is_symmetric(self):

Is this a symmetric exchange

def updated( self, site_1: LatticeSite | None = None, site_2: LatticeSite | None = None, cell_offset: pyspinw.cell_offsets.CellOffset | None = None, name: str | None = None, j: float | None = None):

Get version of this exchange with specified parameters updated

class DiagonalExchange(pyspinw.exchange.Exchange):

Diagonal exchange, which takes the form

H_ij = Jxx_ij S^x_i S^x_j + Jyy_ij S^y_i S^y_j + Jzz_ij S^z_i S^z_j

Parameters
  • site_1: Identifier for S_i
  • site_2: Identifier for S_j
  • j: Vector containing the exchange coefficients for x, y, and z.
DiagonalExchange( site_1: LatticeSite, site_2: LatticeSite, j_x: float, j_y: float, j_z: float, cell_offset: pyspinw.cell_offsets.CellOffset | tuple[int, int, int] | None = None, name: str = '')
exchange_type = 'Diagonal'
parameters = ['j_x', 'j_y', 'j_z']
parameter_defaults = [1.0, 1.0, 1.0]
short_string = 'J'
j_x

Exchange constant for x

j_y

Exchange constant for y

j_z

Exchange constant for z

def is_symmetric(self):

Is this a symmetric exchange

def updated( self, site_1: LatticeSite | None = None, site_2: LatticeSite | None = None, cell_offset: pyspinw.cell_offsets.CellOffset | None = None, name: str | None = None, j_x: float | None = None, j_y: float | None = None, j_z: float | None = None):

Get version of this exchange with specified parameters updated

class XYExchange(pyspinw.exchange.Exchange):

"XY" exchange, which takes the form

H_ij = J_ij (S^x_i S^x_j + S^y_i S^y_j)

Parameters
  • site_1: Identifier for S_i
  • site_2: Identifier for S_j
  • j: The exchange coefficient for the x and y components.
XYExchange( site_1: LatticeSite, site_2: LatticeSite, j: float, cell_offset: pyspinw.cell_offsets.CellOffset | tuple[int, int, int] | None = None, name: str = '')
exchange_type = 'XY'
parameters = ['j']
parameter_defaults = [1.0]
short_string = 'J'
j

Exchange constant for x and y

def is_symmetric(self):

Is this a symmetric exchange

def updated( self, site_1: LatticeSite | None = None, site_2: LatticeSite | None = None, cell_offset: pyspinw.cell_offsets.CellOffset | None = None, name: str | None = None, j: float | None = None):

Get version of this exchange with specified parameters updated

class IsingExchange(pyspinw.exchange.Exchange):

Ising exchange (z component only), which takes the form

H_ij = J_ij S^z_i S^z_j

Parameters
  • site_1: Identifier for S_i
  • site_2: Identifier for S_j
  • j: Scalar. The exchange coefficient J_ij.
IsingExchange( site_1: LatticeSite, site_2: LatticeSite, j_z: float, cell_offset: pyspinw.cell_offsets.CellOffset | tuple[int, int, int] | None = None, name: str = '')
exchange_type = 'Ising'
parameters = ['j_z']
parameter_defaults = [1.0]
short_string = 'J'
j_z

Exchange constant for z

def updated( self, site_1: LatticeSite | None = None, site_2: LatticeSite | None = None, cell_offset: pyspinw.cell_offsets.CellOffset | None = None, name: str | None = None, j_z: float | None = None):

Get version of this exchange with specified parameters updated

def is_symmetric(self):

Is this a symmetric exchange

class DMExchange(pyspinw.exchange.Exchange):

Dzyaloshinskii–Moriya exchange, which takes the form

H_ij = D_ij (S_i x S_j)

Parameters
  • site_1: Identifier for S_i
  • site_2: Identifier for S_j
  • d_x: x component of the d vector above
  • d_y: x component of the d vector above
  • d_z: x component of the d vector above
DMExchange( site_1: LatticeSite, site_2: LatticeSite, d_x: float, d_y: float, d_z: float, cell_offset: pyspinw.cell_offsets.CellOffset | tuple[int, int, int] | None = None, name: str = '')
exchange_type = 'Dzyaloshinskii-Moriya'
parameters = ['d_x', 'd_y', 'd_z']
parameter_defaults = [1.0, 1.0, 1.0]
short_string = 'DM'
d_x

DM exchange constant for x

d_y

DM exchange constant for y

d_z

DM exchange constant for z

def updated( self, site_1: LatticeSite | None = None, site_2: LatticeSite | None = None, cell_offset: pyspinw.cell_offsets.CellOffset | None = None, name: str | None = None, d_x: float | None = None, d_y: float | None = None, d_z: float | None = None):

Get version of this exchange with specified parameters updated

def is_symmetric(self):

Is this a symmetric exchange

class InPlaneFilter(pyspinw.exchangegroup.DirectionalityFilter):

Selects vectors in a given plane (specified by normal)

InPlaneFilter(direction: ArrayLike, max_dev_angle_deg: float = 0.01)
direction
in_plane_dev_num
def accept(self, vector):

DirectionalityFilter implementation: return True if in the plane normal to provided vector

class InDirectionFilter(pyspinw.exchangegroup.DirectionalityFilter):

Selects vectors in a given direction

InDirectionFilter(direction: ArrayLike, max_dev_angle_deg: float = 0.01)
direction
in_direction_dev_num
def accept(self, vector):

DirectionalityFilter implementation: return True if in a similar direction

class BiDirectionFilter(pyspinw.exchangegroup.DirectionalityFilter):

Selects vectors in a given direction

BiDirectionFilter(direction: ArrayLike, max_dev_angle_deg: float = 0.01)
direction
in_direction_dev_num
def accept(self, vector):

DirectionalityFilter implementation: return True if in a similar direction

class Structure(pyspinw.serialisation.SPWSerialisable):

Representation of the magnetic structure

Structure( sites: list[LatticeSite], unit_cell: UnitCell, spacegroup: pyspinw.symmetry.group.SymmetryGroup | None = None, supercell: pyspinw.symmetry.supercell.Supercell | None = None)
def full_structure_site_list(self):

All the sites in the structure

def matplotlib_site_data(self):

Data for making matplotlib scatter plots of sites

def expand(self):

Expand supercell into a single, bigger cell

def without_nonmagnetic(self) -> Structure:

Get a copy of this structure with non-magnetic sites removed

sites: list[LatticeSite]

Get the sites used to define the structure and implied by symmetry

def sites_by_name(self, regex) -> list[LatticeSite]:

Get sites where name matches regex

spacegroup: pyspinw.symmetry.group.SpaceGroup | pyspinw.symmetry.group.MagneticSpaceGroup

Get the spacegroup

unit_cell: UnitCell

Get the unit cell

supercell: pyspinw.symmetry.supercell.Supercell

Get the supercell

class Hamiltonian(pyspinw.serialisation.SPWSerialisable):

Hamiltonian base class

Hamiltonian( structure: Structure, exchanges: list[pyspinw.exchange.Exchange], anisotropies: list[Anisotropy] | None = None)
serialisation_name = 'hamiltonian'
structure

Get the magnetic structure

exchanges

Get the exchanges

def exchanges_by_name(self, regex):

Get list of exchanges whose names match the regex

anisotropies

Get the anisotropies

text_summary: str

String giving details of the system

def expanded(self):

Expand the supercell structure into a single cell structure

def without_nonmagnetic(self):

Get a copy of this Hamiltonian with the nonmagnetic sites removed

def sites_by_name(self, regex) -> list[LatticeSite]:

Get sites where name matches regex

def print_summary(self):

Print a textual summary to stdout

@check_sizes(q_vectors=(-1, 3), field=(3,), allow_nones=True, force_numpy=True)
def energies_and_intensities( self, q_vectors: numpy.ndarray, field: ArrayLike | None = None, use_rust: bool = True, use_rotating: bool = True, intensity_unit: IntensityUnits | str = 'cell'):

Calculate the energy levels of the system for the given q-vectors.

Parameters
  • q_vectors: required An array of q-vectors
  • field: Optional field direction
  • use_rust: Whether to use Rust or Python calculator (default: True)
  • use_rotating: Whether to use the rotating frame calculator if possible (default: True)
  • intensity_unit: Whether to normalise intensity per unit cell or spin (default: 'cell')
def spaghetti_plot_dual( self, path: Path, field: ArrayLike | None = None, show: bool = True, new_figure: bool = True, use_rust: bool = True, use_rotating: bool = True, intensity_unit: IntensityUnits | str = 'cell', scale: str = 'linear'):

Create a spaghetti diagram with energy top and intensity bottom

def spaghetti_plot( self, path: Path, evect: ArrayLike | None = None, dE: float | Callable | None = None, vmin: float = 0, vmax: float | None = None, field: ArrayLike | None = None, show: bool = True, new_figure: bool = True, use_rust: bool = True, use_rotating: bool = True, intensity_unit: IntensityUnits | str = 'cell', scale: str = 'linear'):

Create a spaghetti diagram with intensity as colorfill overplotted by mode energies

def parameterize( self, *parameters: Union[str, list[str], list[tuple[Union[pyspinw.exchange.Exchange, Anisotropy, str], str]], tuple[Sequence[Union[pyspinw.exchange.Exchange, Anisotropy, str]], str], tuple[pyspinw.exchange.Exchange | Anisotropy | str, str]], find_ground_state_with: dict | None = None) -> pyspinw.hamiltonian.HamiltonianParameterization:

Get a function that maps floats to a hamiltonian with the floats controlling the specified parameters

def sorted_positive_energies( self, path: Path, field: ArrayLike | None = None, use_rust: bool = True) -> list[numpy.ndarray]:

Return energies as series corresponding to q, sorted by energy

def energy_plot( self, path: Path, field: ArrayLike | None = None, show: bool = True, new_figure: bool = True, use_rust: bool = True):

Create a spaghetti diagram

def ground_state( self, fixed: list[LatticeSite] | None = None, planar: list[LatticeSite | tuple[LatticeSite, ArrayLike]] | None = None, planar_axis: ArrayLike | None = None, field: ArrayLike | None = None, step_size: float = 0.1, initial_randomisation: pyspinw.calculations.energy_minimisation.InitialRandomisation | str = <InitialRandomisation.JITTER: 'jitter'>, seed: int | None = None, rtol: float = 1e-10, atol: float = 1e-12, max_iters: int = 1000, verbose: bool = True):

Get the classical ground state via gradient descent

For more direct control, use the ClassicalEnergyMinimisation class

Parameters
  • fixed: List of sites that should be ignored by the minimisation, i.e. fixed in place
  • planar: List of sites, or (site, axis) tuples that should be constrained to a plane
  • planar_axis: Axis to use for planar constraints if not specified explicitly, default=[0,0,1]
  • field: Magnetic field applied
  • step_size: Size of step to make relative to the force, smaller values than the default might be needed for systems with high energy.
  • initial_randomisation: Option to RANDOMISE or JITTER the starting state, default JITTER, can also be NONE
  • seed: Seed to use in any randomisation steps
  • rtol: Convergence criterion, stop when [energy change] < rtol x [initial energy change]
  • atol: Convergence criterion, stop when [energy change] < atol
  • max_iters: Limit on the number of iterations
  • verbose: Print information about the process to stdout

:returns: A new Hamiltonian with optimised spin state

class UnitCell(pyspinw.symmetry.unitcell.RawUnitCell):

A Unit Cell Definition

UnitCell( a: float, b: float, c: float, alpha: float = 90, beta: float = 90, gamma: float = 90, ab_normal: tuple[float, float, float] = (0, 0, 1), direction: tuple[float, float, float] | None = None)

See ase.geometry.cell.cellpar_to_cell for details of parameters

a
b
c
alpha
beta
gamma
ab_normal
direction
abc
def updated( self, a: float | None = None, b: float | None = None, c: float | None = None, alpha: float | None = None, beta: float | None = None, gamma: float | None = None, ab_normal: tuple[float, float, float] | None = None, direction: tuple[float, float, float] | None = None, replace_direction=False):

Create a new unit cell with updated parameters

:returns: a new unit cell

class CoordsUnits(enum.Enum):

Types of coordinate system

XYZ = <CoordsUnits.XYZ: 'xyz'>
LU = <CoordsUnits.LU: 'lu'>
class IntensityUnits(enum.Enum):

Output intensity units

PERCELL = <IntensityUnits.PERCELL: 'spin length per cell'>
PERSPIN = <IntensityUnits.PERSPIN: 'spin length per spin'>
BARNPERATOM = <IntensityUnits.BARNPERATOM: 'barns / sr / meV / atom'>
BARNPERCELL = <IntensityUnits.BARNPERCELL: 'barns / sr / meV / cell'>
@check_sizes(directions=('n', 3), phases=('n',), force_numpy=True, allow_nones=True)
def propagation_vectors( directions: numpy.ndarray, phases: numpy.ndarray | None = None, incommensurate: bool = False) -> list[PropagationVector]:

Create list of propagation vectors

Parameters
  • directions: n-by-3 matrix of directions (in lattice units)
  • phases: n vector of phases
  • incommensurate: Whether or not to set them to be incommensuate
@check_sizes(directions=('n', 3), phases=('n',), force_numpy=True, allow_nones=True)
def rotation_supercell( directions: ArrayLike, axes: ArrayLike, phases: ArrayLike | None = None, scaling: tuple[int, int, int] = (1, 1, 1)):

Create a supercell that rotates spins as we move along the propagation vector

Parameters
  • directions: propagation vector directions
  • axes: rotation axes for each propagation vector, or if only a single axis is specified, apply it to all of them
  • phases: Phases of the propagation vectors, 0.0 means starting with the spin as specified on the site
  • scaling: Make a larger supercell by tiling the result this many times in each axis
@check_sizes(perpendicular=(3,), propagation=(3,))
def helical_supercell(perpendicular: ArrayLike, propagation: ArrayLike):

Generate a helical supercell

Parameters
  • perpendicular: (3-vector) Direction perpendicular to propagation vector, needed to specify "start" cell
  • propagation: (3-vector) Propagation vector
@check_sizes(directions=('n', 3), phases=('n',), force_numpy=True, allow_nones=True)
def summation_supercell( directions: numpy.ndarray, phases: numpy.ndarray | None = None, scaling: tuple[int, int, int] = (1, 1, 1)):

Create a supercell based on the propagation vectors and partial spins

i.e. $m = \sum_j mu_j exp(2 \pi i d_j.r + \phi_j)$

Parameters
  • directions: propagation vector directions
  • phases: Phases of the propagation vectors, 0.0 means starting with the spin as specified on the site
  • scaling: Make a larger supercell by tiling the result this many times in each axis
def spacegroup(search_string: str):

Get a spacegroup by name or symmetry operations

The searches are whitespace and case insensitive.

Examples: The following are equivalent: spacegroup("P1") spacegroup("p1") spacegroup("x,y,z")

The following are equivalent:
    spacegroup("P-1")
    spacegroup("p-1")
    spacegroup("x,y,z; -x,-y,-z")

Spacegroups with multiple settings sometimes need to have it specified, but some don't:
    spacegroup("R3")  **fails**
    spacegroup("R3H")  **hexagonal setting**
    spacegroup("R3R")  **rhombohedral setting**

    spacegroup("B2/m") **this setting of C2/m**
    spacegroup("B 1 2/m 1") **another way for the same group**

    spacegroup("P 4/n 2/b 2/m : 1") **setting 1**
    spacegroup("P 4/n 2/b 2/m : 1") **setting 2**
@check_sizes(direction=(3,), force_numpy=True)
def filter( direction: ArrayLike, perpendicular: bool = False, symmetric: bool = False, max_dev_angle_deg: float = 0.01) -> pyspinw.exchangegroup.DirectionalityFilter:

Create a filter for directions (helper method for exchanges)

Parameters
  • direction: If not perpendicular, allowed direction of exchange If perpendicular, normal to plane containing exchange
  • perpendicular: Constrain to a line (perpendicular=False) or a plane (perpendicular=True)
  • symmetric: In the not perpendicular case, symmetric True generates exchanges in both directions
  • max_dev_angle_deg: Angular tolerance for the direction/normal in degrees

:returns: A DirectionalityFilter object that can be used to select exchanges in particular directions

def generate_exchanges( sites: list[LatticeSite] | Structure, unit_cell: UnitCell | None = None, exchange_type: type[pyspinw.exchange.Exchange] = <class 'HeisenbergExchange'>, bond: int = 0, max_distance: float = 0.0, min_distance: float = 0.0, direction_filter: pyspinw.exchangegroup.DirectionalityFilter | None = None, max_order: int | None = None, j: float | None = None, j_x: float | None = None, j_y: float | None = None, j_xy: float | None = None, j_z: float | None = None, d_x: float | None = None, d_y: float | None = None, d_z: float | None = None, exchange_parameters: dict | None = None, naming_pattern: str | None = None):

Automatically creates a list of exchanges

Parameters
  • sites: required List of sites to make exchanges between or a Structure object
  • unit_cell: Unit cell (needed if first argument is a list of sites)
  • exchange_type: Type of exchange (defaults to HeisenbergExchange)
  • bond: The bond index (If this is given the _distance parameters are ignored)
  • max_distance: Maximum Cartesian distance (in Angstrom) at which exchanges are made
  • min_distance: Minimum Cartesian distance (in Angstrom) at which exchanges are made
  • direction_filter: Supply a DirectionalityFilter object (e.g. using filter) to only create exchanges in certain directions
  • max_order: Maximum "order" of exchanges :param j" Constant for scalar valued Heisenberg exchanges (only needed for Heisenberg) :param j_x" Constant for x component of Heisenberg-like exchanges (only needed for Diagonal) :param j_y" Constant for y component of Heisenberg-like exchanges (only needed for Diagonal) :param j_z" Constant for z component of Heisenberg-like exchanges (only needed for Diagonal, Ising and XY) :param j_xy" Constant for x and y components of Heisenberg-like exchanges (only needed for XY and XXZ) :param d_x" Constant for x component of Dzyaloshinskii-Moriya exchange (DM) :param d_y" Constant for y component of Dzyaloshinskii-Moriya exchange (DM) :param d_z" Constant for z component of Dzyaloshinskii-Moriya exchange (DM)
  • exchange_parameters: Parameters can be supplied in a dictionary instead
  • naming_pattern: String used to assign names to exchanges, see apply_naming_convention

:returns: list of exchanges

@check_sizes(axis=(3,), force_numpy=True)
def axis_anisotropies( sites: list[LatticeSite] | Structure, a: float, axis: ArrayLike = [0, 0, 1]):

Create anisotropy objects with magnitude a in direction axis for each site

@check_sizes(matrix=(3, 3), force_numpy=True)
def matrix_anisotropies( sites: list[LatticeSite] | Structure, matrix: ArrayLike):

Create anisotropy objects specified by a matrix, the same for each site

def generate_sites( positions: ArrayLike, spins: ArrayLike | None = None, names: list[str] | None = None) -> list[LatticeSite]:

Create a list of lattice sites

Parameters
  • positions: positions of the sites
  • spins: spins of the sites, if not specified, they will be set to zero
  • names: (optional) a list of names for sites
def generate_structure( unit_cell: UnitCell, positions: ArrayLike, spins: ArrayLike, propagation_vectors: ArrayLike | None = None, names: list[str] | None = None, magnitudes: ArrayLike | None = None, positions_unit: CoordsUnits | str = 'lu', spins_unit: CoordsUnits | str = 'xyz') -> Structure:

Creates a magnetic structure from a list of positions and spins

Parameters
  • unit_cell: a UnitCell object
  • positions: positions of the sites
  • spins: spins of the sites
  • perpendicular: vector perpendicular to helix plane of rotation
  • propagation_vectors: the propagation vector(s)
  • names: (optional) a list of names for sites
  • magnitudes: (optional) a list of spin magnitudes (spin length S) If not specified, the norm of the spins vectors will be used as the spin length
  • positions_units: the units for atomic positions; either 'lu' or 'xyz' (default: 'lu', lattice units)
  • spins_units: the units for the magnetic spin directions; either 'lu' or 'xyz' (default: 'xyz', Cartesian axis with x||a)
  • convert_to_cell_with: (optional) Must be specified if positions_units is not 'lu' and spins_units is not 'xyz' and allows conversion from those units to the default used in LatticeSite. (see pyspinw.UnitCell.spin_fractional_to_cartesian and pyspinw.UnitCell.spin_cartesian_to_fractional`)
def generate_helical_structure( unit_cell: UnitCell, positions: ArrayLike, spins: ArrayLike, perpendicular: ArrayLike, propagation_vector: ArrayLike, names: list[str] | None = None, magnitudes: ArrayLike | None = None, positions_unit: CoordsUnits | str = 'lu', spins_unit: CoordsUnits | str = 'xyz') -> Structure:

Creates a helical structure with a propagation vector and plane normal

Parameters
  • unit_cell: a UnitCell object
  • positions: positions of the sites
  • spins: spins of the sites
  • perpendicular: vector perpendicular to helix plane of rotation
  • propagation_vector: the propagation vector
  • names: (optional) a list of names for sites
  • magnitudes: (optional) a list of spin magnitudes (spin length S) If not specified, the norm of the spins vectors will be used as the spin length
  • positions_units: the units for atomic positions; either 'lu' or 'xyz' (default: 'lu', lattice units)
  • spins_units: the units for the magnetic spin directions; either 'lu' or 'xyz' (default: 'xyz', Cartesian axis with x||a)
  • convert_to_cell_with: (optional) Must be specified if positions_units is not 'lu' and spins_units is not 'xyz' and allows conversion from those units to the default used in LatticeSite. (see pyspinw.UnitCell.spin_fractional_to_cartesian and pyspinw.UnitCell.spin_cartesian_to_fractional`)
class SummationSupercell(pyspinw.symmetry.supercell.CommensurateSupercell):

Supercell with spins defined by

m = sum(m_j exp(2 pi i r.k_j)).real

SummationSupercell( propagation_vectors: list[CommensuratePropagationVector], scaling: tuple[int, int, int] | None = None)
supercell_name = 'summation'
def spin_calculation( self, spin_data: numpy.ndarray, cell_offset: pyspinw.cell_offsets.CellOffset):

Calculate spin at a given cell offset

def spin_derivative( self, supercell_component_index: int, cell: pyspinw.cell_offsets.CellOffset):

Derivative of the spin at a given site with respect to one component of it

def n_components(self) -> int:

Number of spin components/propagation vectors

def summation_form(self) -> SummationSupercell:

Convert to summation form (it is already in this form, but not all Supercells are)

class RotationSupercell(pyspinw.symmetry.supercell.Supercell):

A supercell defined by spins which rotates in a plane and a single propagation vector

RotationSupercell( perpendicular: ArrayLike, propagation_vector: ArrayLike | PropagationVector)
supercell_name = 'rotation'
perpendicular
propagation_vector
def spin_calculation( self, spin_data: numpy.ndarray, cell_offset: pyspinw.cell_offsets.CellOffset):

Calculate spin at a given cell offset

def n_components(self) -> int:

Number of propagation vectors in this supercell

def cell_size(self) -> tuple[int, int, int]:

How big is this supercell

def summation_form(self) -> pyspinw.symmetry.supercell.Supercell:

Convert into summation form

def approximant( self, max_denominator: int = 1000) -> TransformationSupercell:

Convert to an approximate commensurate supercell

class TransformationSupercell(pyspinw.symmetry.supercell.CommensurateSupercell):

Supercell with spins defined by the following equation:

m = prod(M_i^{r.k}) m0

where m0 is the existing spin at a given site

TransformationSupercell( transforms: list[tuple[CommensuratePropagationVector, pyspinw.symmetry.supercell.SupercellTransformation | None]], scaling=(1, 1, 1))
supercell_name = 'transformation'
def spin_calculation( self, spin_data: numpy.ndarray, cell_offset: pyspinw.cell_offsets.CellOffset):

Calculate the spin based on the spin data for a given site

def spin_derivative( self, supercell_component_index: int, cell: pyspinw.cell_offsets.CellOffset):

Derivative of the spin at a given site with respect to one component of it

def summation_form(self) -> pyspinw.symmetry.supercell.Supercell:

Convert into summation form

def n_components(self) -> int:

Number of spin components/propagation vectors

class TiledSupercell(pyspinw.symmetry.supercell.CommensurateSupercell):

Trivial supercell, just a single unit cell

TiledSupercell(scaling=(1, 1, 1))
supercell_name = 'trivial'
def spin_calculation( self, spin_data: numpy.ndarray, cell_offset: pyspinw.cell_offsets.CellOffset):

Get the spin for a given cell, and the specified spin data

def cell_size(self) -> tuple[int, int, int]:

How big is this supercell

def summation_form(self) -> pyspinw.symmetry.supercell.Supercell:

Get this supercell in summation form

def spin_derivative( self, supercell_component_index: int, cell: pyspinw.cell_offsets.CellOffset):

Derivative of the spin at a given site with respect to one component of it

def n_components(self) -> int:

Number of spin components/propagation vectors

class PropagationVector(pyspinw.serialisation.SPWSerialisable):

Propagation vector

PropagationVector( i: fractions.Fraction | float, j: fractions.Fraction | float, k: fractions.Fraction | float, phase: float = 0.0)
serialisation_name = 'propagation_vector'
i
j
k
phase
vector

As a numpy vector

def dot(self, cell_offset: pyspinw.cell_offsets.CellOffset):

Dot product with a cell offset

def uncorrected_phase_position(self, site: LatticeSite):

Get the position of a site along the propagation vector, from (0,0,0), ignoring the phase correction

def corrected_phase_position(self, site: LatticeSite):

Get the position of a site along the propagation vector, from (0,0,0), including the phase correction

class CommensuratePropagationVector(pyspinw.PropagationVector):

Propagation vector with rational values

CommensuratePropagationVector( i: fractions.Fraction | float, j: fractions.Fraction | float, k: fractions.Fraction | float, phase: float = 0.0, max_denominator=1000)
class SingleCrystal(pyspinw.sample.Sample3D):

Specifies a single crystal sample

SingleCrystal(hamiltonian: Hamiltonian)
class Multidomain(pyspinw.sample.Sample3D):

Sample consisting of multiple domains

Multidomain( hamiltonian: Hamiltonian, domains: list[CrystalDomain | tuple[ArrayLike, float]])
weights
class CrystalDomain:

Orientation and amount of crystalline domain (e.g. one of a twin, or a domain in the traditional sense)

@check_sizes(transformation=(3, 3), force_numpy=True)
CrystalDomain(transformation: ArrayLike, weighting: float)
transformation
weighting
class Twin(pyspinw.Multidomain):

Specify a twinned crystal.

Special case of multidomain

Twin( hamiltonian: Hamiltonian, relative_rotation: ArrayLike, second_twin_fraction: float)
class Powder(pyspinw.sample.Sample1D):

Sample is a powder

Powder(hamiltonian: Hamiltonian)
def spectrum( self, path: Path1D | pyspinw.path.EmpiricalPath1D | ArrayLike, n_samples: int = 100, method: SphericalPointGeneratorType | str = 'fibonacci', min_energy: float | None = None, max_energy: float | None = None, n_energy_bins: int | None = None, energy_stddev: float | None = None, random_seed: int | None = None, use_rust: bool = True):

Get the powder spectrum

def parameterized_spectrum( self, parameters: Sequence[Union[str, list[str], list[tuple[Union[pyspinw.exchange.Exchange, Anisotropy, str], str]], tuple[Sequence[Union[pyspinw.exchange.Exchange, Anisotropy, str]], str], tuple[pyspinw.exchange.Exchange | Anisotropy | str, str]]], path: Path1D | pyspinw.path.EmpiricalPath1D | ArrayLike, n_samples: int = 100, method: SphericalPointGeneratorType | str = 'fibonacci', min_energy: float | None = None, max_energy: float | None = None, n_energy_bins: int | None = None, energy_stddev: float | None = None, random_seed: int | None = None, use_rust: bool = True, find_ground_state_with: dict | None = None):

Get the powder spectrum as a function of parameters

def show_spectrum( self, path: Path1D | pyspinw.path.EmpiricalPath1D | ArrayLike, n_samples: int = 100, method: SphericalPointGeneratorType | str = 'fibonacci', min_energy: float | None = None, max_energy: float | None = None, n_energy_bins: int | None = None, energy_stddev: float | None = None, random_seed: int | None = None, scaling_method: ScalingMethod | str = 'linear', show_plot: bool = True, new_figure: bool = True, use_rust: bool = True):

Show the powder spectrum

class ScalingMethod(enum.Enum):

Scaling methods for plots

LINEAR = <ScalingMethod.LINEAR: 'linear'>
LOG = <ScalingMethod.LOG: 'log'>
class SphericalPointGeneratorType(enum.Enum):

Different kinds of point generators for spherical integration

FIBONACCI = <SphericalPointGeneratorType.FIBONACCI: 'fibonacci'>
RANDOM = <SphericalPointGeneratorType.RANDOM: 'random'>
GEODESIC = <SphericalPointGeneratorType.GEODESIC: 'geodesic'>
class Path:

Path through q-space

Path( points: ArrayLike, n_points_per_segment: int = 101, labels: list[str] | None = None, avoid_endpoints=True, scale_by_distance=False)
def q_points(self):

Get list of q points

def x_values(self):

x values for plotting

def x_ticks(self):

x positions of ticks used to mark positions on a plot

def x_tick_labels(self):

x-axis tick labels corresponding to tick positions

def format_plot(self, plt_or_fig=None):

Apply formatting to a matplotlib plot/figure/axis

If None, it will import matplotlib.pyplot and work on that

class Path1D(pyspinw.path.Path1DBase):

1D Path, i.e. just values in absolute q

Path1D( q_min: float = 0.0, q_max: float = 1.0, avoid_endpoints=True, n_points: int = 101)
q_min
q_max
n_points
avoid_endpoints
def q_values(self):

Get q magnitudes

def set_up_windows_python_parallelisation():

This needs to be run to enable python parallelisation on windows

Call it like this at the start of your script:

if __name__ == "__main__":
    set_up_windows_python_parallelisation()

    [your code]

Applies freeze_support() and sets a flag to be used elsewhere

def view( object: Hamiltonian | Structure):

Show a Hamiltonian in the viewer

def demos():

Run through general tasks that should test things are installed correctly

def demo_viewer():

Show the viewer with an example

def demo_chains():

Antiferromagnetic chain example