Exchange Parameter#

For the full reference see ExchangeParameter

ExchangeParameter is a wrap around numpy.ndarray with predefined properties specific for the exchange parameter.

Isotropic, anisotropic and DMI parts of exchange matrix are defined as follows:

\[J_{iso} = \dfrac{\text{tr}(\boldsymbol{J})}{3}\]
\[\mathbf{J}_{aniso} = \boldsymbol{J}_{symm} = \dfrac{\boldsymbol{J} + \boldsymbol{J}^T}{2} - \dfrac{1}{3}\text{tr}(\boldsymbol{J})\cdot\mathbf{I}\]
\[\vec{\boldsymbol{D}} = (D_x, D_y, D_z)\]
\[\begin{split}\mathbf{J}_{asymm} = \dfrac{\boldsymbol{J} - \boldsymbol{J}^T}{2} = \begin{bmatrix} 0 & D_z & -D_y \\ -D_z & 0 & D_x \\ D_y & -D_x & 0 \\ \end{bmatrix}\end{split}\]

where \(\boldsymbol{J}\) is the full exchange matrix. Isotropic exchange is a scalar, Anisotropic part is a traceless part of full matrix`s symmetric part and antisymmetric part of full matrix is described by Dzyaloshinskii-Moriya vector.

Creation#

It is created as any instance of a python class. The constructor takes the following arguments:

  • matrix - the \(3 \times 3\) matrix of the exchange parameter.

  • iso - the isotropic part of the exchange parameter.

  • aniso - the anisotropic part of the exchange parameter.

  • dmi - the Dzyaloshinskii-Moriya vector.

The matrix is the main argument and it is used to calculate the other parameters. Other arguments are used to calculate the matrix only if it is not provided.

>>> import radtools as rad
>>> J = rad.ExchangeParameter(iso=1)
>>> J
ExchangeParameter(array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]]))

For the exchange parameter convenient string representation is defined:

>>> print(J)
 1.0000 0.0000 0.0000
 0.0000 1.0000 0.0000
 0.0000 0.0000 1.0000
>>> J = rad.ExchangeParameter(dmi=(1,1,1))
>>> print(J)
  0.0000  1.0000 -1.0000
 -1.0000  0.0000  1.0000
  1.0000 -1.0000  0.0000

Every property of the parameter can be accessed as an attribute. Below we list examples for each group of properties.

Full exchange matrix#

Only full matrix is stored, every other parameter is calculated from it.

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.matrix
array([[1., 2., 3.],
       [4., 5., 6.],
       [7., 8., 9.]])

Symmetric and asymmetric part can be accessed as:

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.symm_matrix
array([[1., 3., 5.],
       [3., 5., 7.],
       [5., 7., 9.]])
>>> J.asymm_matrix
array([[ 0., -1., -2.],
       [ 1.,  0., -1.],
       [ 2.,  1.,  0.]])

Istoropic exchange#

Isotropic exchange is a scalar and it is defined as a trace of the exchange matrix:

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.iso
5.0

For isotroic exchange matrix form is defined:

>>> J = rad.ExchangeParameter(iso=1)
>>> J.matrix
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

Anisotropic exchange#

Note

Anisotropic exchange is a traceless part of symmetric part of exchange matrix.

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.aniso
array([[-4.,  3.,  5.],
       [ 3.,  0.,  7.],
       [ 5.,  7.,  4.]])

For anisotropic exchange usually reduced to the diagonal part, thus diagonal part and its matrix form is explicitly defined:

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.aniso_diagonal
array([-4.,  0.,  4.])
>>> J.aniso_diagonal_matrix
array([[-4.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  4.]])

Dzyaloshinskii-Moriya interaction#

Note

Dzyaloshinskii-Moriya interaction is an antisymmetric part of exchange matrix.

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.dmi
array([-1.,  2., -1.])

Matrix form of DMI is accessible as:

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.dmi_matrix
array([[ 0., -1., -2.],
       [ 1.,  0., -1.],
       [ 2.,  1.,  0.]])

Two useful values are defined for DMI: its module and relative strength to isotropic exchange:

\[\frac{\vert \vec{\boldsymbol{D}}\vert}{\vert J\vert}\]
>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> print(f"{J.dmi_module:.4f}")
2.4495
>>> print(f"{J.rel_dmi:.4f}")
0.4899

Arithmetic operations#

Arithmetic operations are defined for the exchange parameter. They act on the full exchange matrix and return ExchangeParameter instance.

>>> J1 = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J2 = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J1 + J2
ExchangeParameter(array([[ 2.,  4.,  6.],
       [ 8., 10., 12.],
       [14., 16., 18.]]))
>>> J1 - J2
ExchangeParameter(array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]]))
>>> 2 * J2
ExchangeParameter(array([[ 2.,  4.,  6.],
       [ 8., 10., 12.],
       [14., 16., 18.]]))
>>> J2 / 2
ExchangeParameter(array([[0.5, 1. , 1.5],
       [2. , 2.5, 3. ],
       [3.5, 4. , 4.5]]))
>>> J1 // 3
ExchangeParameter(array([[0., 0., 1.],
       [1., 1., 2.],
       [2., 2., 3.]]))
>>> J1 % 3
ExchangeParameter(array([[1., 2., 0.],
       [1., 2., 0.],
       [1., 2., 0.]]))
>>> -J1
ExchangeParameter(array([[-1., -2., -3.],
       [-4., -5., -6.],
       [-7., -8., -9.]]))
>>> abs(-J1)
ExchangeParameter(array([[1., 2., 3.],
       [4., 5., 6.],
       [7., 8., 9.]]))
>>> J1 == J2
True
>>> J1 != J2
False

Matrix multiplication works with ExchangeParameter instance as well, but it returns numpy.ndarray instance:

>>> import numpy as np
>>> J1 = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> a = np.eye(3)
>>> J1 @ a
array([[1., 2., 3.],
       [4., 5., 6.],
       [7., 8., 9.]])

NumPy interface#

Array interface is defined for the exchange parameter. It aims any numpy function onto the full exchange matrix.

Only transpose is defined directly in order to return ExchangeParameter instance:

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> J.T
ExchangeParameter(array([[1., 4., 7.],
       [2., 5., 8.],
       [3., 6., 9.]]))

Any other numpy function should work as expected, however it is not tested:

>>> J = rad.ExchangeParameter(matrix=[[1,2,3],[4,5,6],[7,8,9]])
>>> np.sum(J)
45.0
>>> np.diag(J)
array([1., 5., 9.])
>>> np.iscomplex(J)
array([[False, False, False],
       [False, False, False],
       [False, False, False]])