SpinHamiltonian#

For the full reference see SpinHamiltonian.

Main idea of the spin Hamiltonian structure could be expressed as

(atom1, atom2, (i,j,k)) -> exchange_parameter

where atom1 and atom2 are instances of Atom, (i,j,k) is a tuple of integers, which defines the unit cell (in relative coordinates). exchange_parameter is an instance of ExchangeParameter. The SpinHamiltonian supports dictionary-like access to the exchange parameters (see examples).

Import#

>>> # Exact import
>>> from radtools.spinham.hamiltonian import SpinHamiltonian
>>> # Explicit import
>>> from radtools.spinham import SpinHamiltonian
>>> # Recommended import
>>> from radtools import SpinHamiltonian

For the examples in this page we need additional import and some predefined variables:

>>> from radtools import ExchangeParameter, Atom, Crystal, lattice_example
>>> Cr = Atom("Cr", spin=1.5)
>>> Cr1 = Atom("Cr", position=(0.5, 0, 0))
>>> Cr2 = Atom("Cr", position=(1, 0, 0))
>>> J1 = ExchangeParameter(iso=1)
>>> J2 = ExchangeParameter(iso=2)
>>> tet_lattice = lattice_example("TET")
>>> crystal = Crystal(a1 = [1, 0, 0], a2 = [0, 1, 0], a3 = [0, 0, 1], atoms=[Cr])

Creation#

Hint

For the creation of the spin Hamiltonian from the TB2J file see load_tb2j_model().

>>> hamiltonian = SpinHamiltonian()

SpinHamiltonian is a child of Crystal. Constructor can take an instance of the Crystal class or keyword arguments, which will be passed to the Crystal constructor:

>>> hamiltonian = SpinHamiltonian(crystal)
>>> # Is equivalent to
>>> hamiltonian = SpinHamiltonian(a1 = [1, 0, 0], a2 = [0, 1, 0], a3 = [0, 0, 1], atoms=[Cr])

For the full list of constructor parameters see SpinHamiltonian documentation.

After the creation of the SpinHamiltonian you need to add atoms and bonds to it.

Adding atoms#

Atoms can be passed to the constructor of the SpinHamiltonian or added later. Atom addition is inherited from the Crystal:

>>> hamiltonian = SpinHamiltonian()
>>> len(hamiltonian.atoms)
0
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(1, 0, 0))
>>> hamiltonian.add_atom("Br")
>>> len(hamiltonian.atoms)
2

Adding bonds#

The bond is added to the Hamiltonian via SpinHamiltonian.add_bond() method:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> hamiltonian["Cr", "Cr", (1, 0, 0)].iso
1.0

Note

The bond is added to the Hamiltonian, but no atom is explicitly added to the crystal. You can skip the atom addition if you are using Atom instances, not the names in the SpinHamiltonian.add_bond() method. The atom will be silently added to the system. When atom`s name is used, atom object is extracted from the spin Hamiltonian, thus it has to be explicitly added first:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond("Cr", "Cr", (1, 0, 0), iso=1)
Traceback (most recent call last):
...
ValueError: No match found for name = Cr, index = None
>>> hamiltonian.add_atom(Cr)
>>> hamiltonian.add_bond("Cr", "Cr", (1, 0, 0), iso=1)
>>> hamiltonian["Cr", "Cr", (1, 0, 0)].iso
1.0

Equivalent way to add bond:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian[Cr, Cr, (1, 0, 0)] = J1
>>> hamiltonian[Cr, "Cr", (2, 0, 0)] = J2
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
1.0
>>> hamiltonian[Cr, Cr, (2, 0, 0)].iso
2.0

Note

If the atom is already added to the Hamiltonian, then you can use both atom`s name and the instance of the atom class. If you have more then one atom with the same name in the Hamiltonian, then you have to use Atom.fullname() instead of the name:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_atom(Cr1)
>>> hamiltonian.add_atom(Cr2)
>>> hamiltonian[Cr1, Cr2, (1, 0, 0)] = J2
>>> hamiltonian[Cr1, Cr2, (1, 0, 0)].iso
2.0
>>> hamiltonian["Cr", "Cr", (1, 0, 0)] = J1
Traceback (most recent call last):
...
ValueError: Multiple matches found for name = Cr, index = None
>>> hamiltonian["Cr__1", "Cr__2", (1, 0, 0)] = J1
>>> hamiltonian["Cr__1", "Cr__2", (1, 0, 0)].iso
1.0

Removing atoms#

Removing an atom from the SpinHamiltonian is not the same as removing it from the Crystal. When atom is removed from the SpinHamiltonian all bonds, which are connected to it are removed as well.

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(1, 0, 0))
>>> hamiltonian.add_bond("Cr", "Cr", (1, 0, 0), iso=1)
>>> len(hamiltonian)
1
>>> len(hamiltonian.atoms)
1
>>> hamiltonian.remove_atom("Cr")
>>> len(hamiltonian)
0
>>> len(hamiltonian.atoms)
0

Removing bonds#

To remove the bond use SpinHamiltonian.remove_bond() method:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> (Cr, Cr, (1, 0, 0)) in hamiltonian
True
>>> hamiltonian.remove_bond("Cr", Cr, (1, 0, 0))
>>> (Cr, Cr, (1, 0, 0)) in hamiltonian
False

Hint

Note how we used atom name to remove the bond.

Equivalent way to delete bond mimics the dictionary behaviour:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> (Cr, Cr, (1, 0, 0)) in hamiltonian
True
>>> del hamiltonian[Cr, Cr, (1, 0, 0)]
>>> (Cr, Cr, (1, 0, 0)) in hamiltonian
False

Magnetic atoms#

Atoms, which has at least one bond attached to them are called magnetic atoms. They could be accessed with SpinHamiltonian.magnetic_atoms property:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(0, 0, 0))
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(1, 0, 0))
>>> hamiltonian.magnetic_atoms
[]
>>> hamiltonian.add_bond("Cr__1", "Cr__1", (0, 1, 0), iso=1)
>>> for atom in hamiltonian.magnetic_atoms:
...     print(atom.fullname)
...
Cr__1
>>> hamiltonian.add_bond("Cr__1", "Cr__2", (0, 0, 0), iso=1)
>>> for atom in hamiltonian.magnetic_atoms:
...     print(atom.fullname)
...
Cr__1
Cr__2

Atom name vs instance#

In many situations atom name (Atom.name) or fullname (Atom.fullname) can be used with the SpinHamiltonian.

You can use name if you have only one atom with this name in the Hamiltonian. Otherwise you have to use fullname. For example:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(0, 0, 0))
>>> # Can use name, since there is only one atom with this name
>>> hamiltonian.add_bond("Cr", "Cr", (0, 1, 0), iso=1)
>>> for atom1, atom2, (i, j, k), J in hamiltonian:
...     print(atom1.fullname, atom2.fullname, (i, j, k), J.iso)
...
Cr__1 Cr__1 (0, 1, 0) 1.0
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(1, 0, 0))
>>> # Have to use fullname, since there are two atoms with the same name
>>> hamiltonian.add_bond("Cr__1", "Cr__1", (0, 1, 0), iso=1)
>>> hamiltonian.add_bond("Cr__1", "Cr__2", (0, 0, 0), iso=2)
>>> for atom1, atom2, (i,j,k), J in hamiltonian:
...     print(atom1.fullname, atom2.fullname, (i, j, k), J.iso)
...
Cr__1 Cr__1 (0, 1, 0) 1.0
Cr__1 Cr__2 (0, 0, 0) 2.0

If you want to get an Atom instance from the SpinHamiltonian you can use SpinHamiltonian.get_atom() method:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(0, 0, 0))
>>> # Can use name, since there is only one atom with this name
>>> hamiltonian.get_atom("Cr").fullname
'Cr__1'
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(1, 0, 0))
>>> # Have to use fullname, since there are two atoms with the same name
>>> hamiltonian.get_atom("Cr__1").fullname
'Cr__1'
>>> hamiltonian.get_atom("Cr__2").fullname
'Cr__2'

Filtering#

Spin Hamiltonian could be filtered by distance, template or set of (i, j, k) tuples (R vectors).

Use SpinHamiltonian.filter() to filter the instance of the SpinHamiltonian and SpinHamiltonian.filtered() to get the filtered copy of the SpinHamiltonian:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_atom("Cr", position=(0.25, 0.25, 0))
>>> hamiltonian.add_atom("Cr", position=(0.75, 0.75, 0))
>>> bonds = [
...     (12, "Cr__1", "Cr__2", (0, 0, 0)),
...     (12, "Cr__2", "Cr__1", (0, 0, 0)),
...     (12, "Cr__1", "Cr__1", (1, 0, 0)),
...     (12, "Cr__1", "Cr__1", (-1, 0, 0)),
...     (12, "Cr__2", "Cr__2", (1, 0, 0)),
...     (12, "Cr__2", "Cr__2", (-1, 0, 0)),
...     (12, "Cr__1", "Cr__1", (0, 2, 0)),
...     (12, "Cr__1", "Cr__1", (0, -2, 0)),
...     (12, "Cr__2", "Cr__2", (0, 2, 0)),
...     (12, "Cr__2", "Cr__2", (0, -2, 0)),
...     (12, "Cr__2", "Cr__1", (2, 2, 0)),
...     (12, "Cr__1", "Cr__2", (-2, -2, 0)),
... ]
>>> for iso, atom1, atom2, R in bonds:
...     hamiltonian.add_bond(atom1, atom2, R, iso=iso)
>>> for atom1, atom2, R, J in hamiltonian:
...     print(atom1.fullname, atom2.fullname, R, J.iso)
...
Cr__1 Cr__2 (0, 0, 0) 12.0
Cr__2 Cr__1 (0, 0, 0) 12.0
Cr__1 Cr__1 (1, 0, 0) 12.0
Cr__1 Cr__1 (-1, 0, 0) 12.0
Cr__2 Cr__2 (1, 0, 0) 12.0
Cr__2 Cr__2 (-1, 0, 0) 12.0
Cr__1 Cr__1 (0, 2, 0) 12.0
Cr__1 Cr__1 (0, -2, 0) 12.0
Cr__2 Cr__2 (0, 2, 0) 12.0
Cr__2 Cr__2 (0, -2, 0) 12.0
Cr__2 Cr__1 (2, 2, 0) 12.0
Cr__1 Cr__2 (-2, -2, 0) 12.0
>>> filtered_hamiltonian = hamiltonian.filtered(max_distance=1)
>>> for atom1, atom2, R, J in filtered_hamiltonian:
...     print(atom1.fullname, atom2.fullname, R, J.iso)
...
Cr__1 Cr__2 (0, 0, 0) 12.0
Cr__2 Cr__1 (0, 0, 0) 12.0
Cr__1 Cr__1 (1, 0, 0) 12.0
Cr__1 Cr__1 (-1, 0, 0) 12.0
Cr__2 Cr__2 (1, 0, 0) 12.0
Cr__2 Cr__2 (-1, 0, 0) 12.0
>>> filtered_hamiltonian = hamiltonian.filtered(min_distance=2.1)
>>> for atom1, atom2, R, J in filtered_hamiltonian:
...     print(atom1.fullname, atom2.fullname, R, J.iso)
...
Cr__2 Cr__1 (2, 2, 0) 12.0
Cr__1 Cr__2 (-2, -2, 0) 12.0
>>> filtered_hamiltonian = hamiltonian.filtered(R_vector=[(0, 0, 0), (1, 0, 0)])
>>> for atom1, atom2, R, J in filtered_hamiltonian:
...     print(atom1.fullname, atom2.fullname, R, J.iso)
...
Cr__1 Cr__2 (0, 0, 0) 12.0
Cr__2 Cr__1 (0, 0, 0) 12.0
Cr__1 Cr__1 (1, 0, 0) 12.0
Cr__2 Cr__2 (1, 0, 0) 12.0
>>> filtered_hamiltonian = hamiltonian.filtered(template=[("Cr__1", "Cr__2", (0, 0, 0))])
>>> for atom1, atom2, R, J in filtered_hamiltonian:
...     print(atom1.fullname, atom2.fullname, R, J.iso)
...
Cr__1 Cr__2 (0, 0, 0) 12.0

Hint

You can combine filtering options together. Only the bonds, which satisfy all the conditions are included in the filtered Hamiltonian.

Energy#

Ferromagnetic energy of the Hamiltonian could be calculated with SpinHamiltonian.ferromagnetic_energy() method:

Note

The notation of the Hamiltonian has to be defined for this method to work.

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(0,0,0))
>>> hamiltonian.add_atom("Cr", spin=1.5, position=(1,0,0))
>>> hamiltonian.add_bond("Cr__1", "Cr__1", (0, 1, 0), iso=1)
>>> hamiltonian.add_bond("Cr__1", "Cr__2", (0, 0, 0), iso=2)
>>> hamiltonian.ferromagnetic_energy()
Traceback (most recent call last):
...
radtools.exceptions.NotationError:
...
>>> hamiltonian.notation = "standard"
>>> hamiltonian.ferromagnetic_energy()
-13.5

Saving#

The Hamiltonian could be saved in as a text file with dump_spinham_txt() function:

>>> from radtools import dump_spinham_txt
>>> hamiltonian = SpinHamiltonian()
>>> # Saves the hamiltonian into the file "hamiltonian.txt"
>>> dump_spinham_txt(hamiltonian, "hamiltonian.txt")

The format of the file is inspired by the output files of the TB2J code. Isotropic exchange is always written. DMI, full matrix and symmetric anisotropic exchange can be removed from the output.

It can be serialized with dump_pickle() function.

>>> from radtools import dump_pickle
>>> hamiltonian = SpinHamiltonian()
>>> # Saves the hamiltonian into the file "hamiltonian.pickle"
>>> dump_pickle(hamiltonian, "hamiltonian")

Hint

Note that the file extension is added automatically only for the dump_pickle() function. It is done intentionally to emphasize that the Hamiltonian is saved in a python-specific binary file.

While the dump_spinham_txt() offers you complete control over the file name.

Dictionary-like behaviour#

Spin Hamiltonian supports the logic of a dictionary, where the keys are the tuples of the form:

\[(\text{atom}_1, \text{atom}_2, (i, j, k))\]

And the values are the ExchangeParameter instances. Key-value pair is called bond. It describes the exchange interaction between two atoms, \(\text{atom}_1\) is always located in the unit cell \((0, 0, 0)\), \(\text{atom}_2\) is located in the unit cell \((i, j, k)\). The coordinate of unit cells are always relative to the lattice vectors.

It supports the following operations:

  • len(hamiltonian) - returns the number of bonds in the Hamiltonian

>>> hamiltonian = SpinHamiltonian()
>>> len(hamiltonian)
0
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> len(hamiltonian)
1
>>> hamiltonian.add_bond(Cr, Cr, (0, 1, 0), iso=2)
>>> len(hamiltonian)
2
  • Iteration over the Hamiltonian returns the key and the value

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> hamiltonian.add_bond(Cr, Cr, (0, 1, 0), iso=2)
>>> for atom1, atom2, (i, j, k), J in hamiltonian:
...     print(atom1.fullname, atom2.fullname, (i, j, k), J.iso)
...
Cr__1 Cr__1 (1, 0, 0) 1.0
Cr__1 Cr__1 (0, 1, 0) 2.0

Note

It does not return only the key as for python dictionaries. It returns the key and the value. This is done to simplify the iteration over the Hamiltonian.

  • in syntax returns True if the bond is present in the Hamiltonian

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> (Cr, Cr, (1, 0, 0)) in hamiltonian
True
>>> (Cr, Cr, (0, 1, 0)) in hamiltonian
False
  • Getting and setting the value of the bond

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian[Cr, Cr, (1, 0, 0)] = J1
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
1.0
  • Deleting the bond

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian[Cr, Cr, (1, 0, 0)] = J1
>>> (Cr, Cr, (1, 0, 0)) in hamiltonian
True
>>> del hamiltonian[Cr, Cr, (1, 0, 0)]
>>> (Cr, Cr, (1, 0, 0)) in hamiltonian
False

Notation examples#

For the detailed explanation of the notation see Notation of spin Hamiltonian.

Setting#

The notation could be defined in three ways:

  • By setting each individual property. For example:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.double_counting = True
>>> hamiltonian.spin_normalized = False
>>> hamiltonian.factor = -1
  • By setting the notation property directly with the tuple of five bool:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.notation = (True, False, -2)
>>> hamiltonian.notation
(True, False, -2.0)
>>> print(hamiltonian.notation_string)
H = -2 \sum_{i,j} S_i J_{ij} S_j
Double counting is present.
Spin vectors are not normalized.
>>> hamiltonian.double_counting
True
>>> hamiltonian.spin_normalized
False
>>> hamiltonian.factor
-2.0
  • By setting the notation property directly with the string:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.notation = 'standard'
>>> hamiltonian.notation
(True, False, -1.0)
>>> print(hamiltonian.notation_string)
H = - \sum_{i,j} S_i J_{ij} S_j
Double counting is present.
Spin vectors are not normalized.
>>> hamiltonian.notation = 'tb2j'
>>> hamiltonian.notation
(True, True, -1.0)
>>> print(hamiltonian.notation_string)
H = - \sum_{i,j} e_i J_{ij} e_j
Double counting is present.
Spin vectors are normalized to 1.
>>> hamiltonian.notation = 'vampire'
>>> hamiltonian.notation
(True, True, -0.5)
>>> print(hamiltonian.notation_string)
H = -1/2 \sum_{i,j} e_i J_{ij} e_j
Double counting is present.
Spin vectors are normalized to 1.
>>> hamiltonian.notation = 'spinw'
>>> hamiltonian.notation
(True, False, 1.0)
>>> print(hamiltonian.notation_string)
H = \sum_{i,j} S_i J_{ij} S_j
Double counting is present.
Spin vectors are not normalized.

Changing#

Once the full notation or any individual property is set, the following redefinition of the notation or corresponding property changes exchange parameters. For example:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
1.0
>>> hamiltonian.notation = (True, False, -1)
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
1.0
>>> # Normalize spins
>>> hamiltonian.notation = (True, True, -1)
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
2.25
>>> # Remove minus sign in the Hamiltonian definition
>>> hamiltonian.notation = (True, True, 1)
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
-2.25

The rule for the notation change is simple: Conserve the value of energy.

Resetting#

If you want to reset the notation once it is set, but keep the parameters intact use SpinHamiltonian.set_interpretation() method:

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.double_counting = True
>>> hamiltonian.spin_normalized = False
>>> hamiltonian.factor = -2
>>> hamiltonian.notation
(True, False, -2.0)
>>> print(hamiltonian.notation_string)
H = -2 \sum_{i,j} S_i J_{ij} S_j
Double counting is present.
Spin vectors are not normalized.
>>> hamiltonian.set_interpretation(double_counting=False, spin_normalized=True)
>>> hamiltonian.notation
(False, True, -2.0)
>>> print(hamiltonian.notation_string)
H = -2 \sum_{i>=j} e_i J_{ij} e_j
No double counting.
Spin vectors are normalized to 1.

Double counting#

>>> hamiltonian = SpinHamiltonian()
>>> hamiltonian.add_bond(Cr, Cr, (1, 0, 0), iso=1)
>>> hamiltonian.notation = "standard"
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso, hamiltonian.ferromagnetic_energy()
(1.0, -4.5)
>>> hamiltonian.double_counting, hamiltonian.ferromagnetic_energy()
(True, -4.5)
>>> hamiltonian.double_counting = False
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
2.0
>>> hamiltonian.double_counting, hamiltonian.ferromagnetic_energy()
(False, -4.5)
>>> hamiltonian.double_counting = True

Double counting and \(S_i^2\) terms#

Double counting behaves different if atom1 = atom2 and (i, j, k) = (0, 0, 0):

>>> spinham = SpinHamiltonian()
>>> spinham.add_atom("Mn", (0, 0, 0))
>>> spinham.add_bond("Mn", "Mn", (1, 0, 0), iso=1)
>>> spinham.add_bond("Mn", "Mn", (0, 0, 0), iso=1)
>>> spinham.notation = (1, 1, 1)
>>> spinham.double_counting
True
>>> # Double counting is present (0, 0, 0) bond is not doubled.
>>> for a1, a2, R, J in spinham:
...     print(R)
...
(1, 0, 0)
(0, 0, 0)
(-1, 0, 0)
>>> print(spinham["Mn", "Mn", (1, 0, 0)].iso, spinham["Mn", "Mn", (0, 0, 0)].iso)
1.0 1.0
>>> spinham.double_counting = False
>>> for a1, a2, R, J in spinham:
...     print(R)
...
(1, 0, 0)
(0, 0, 0)
>>> # Parameter for (0, 0, 0) does not change
>>> print(spinham["Mn", "Mn", (1, 0, 0)].iso, spinham["Mn", "Mn", (0, 0, 0)].iso)
2.0 1.0

Spin normalization#

>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
1.0
>>> hamiltonian.spin_normalized, hamiltonian.ferromagnetic_energy()
(False, -4.5)
>>> # Spin of Cr atom is 1.5
>>> hamiltonian.spin_normalized = True
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
2.25
>>> hamiltonian.spin_normalized, hamiltonian.ferromagnetic_energy()
(True, -4.5)
>>> hamiltonian.spin_normalized = False

Factor#

>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
1.0
>>> hamiltonian.factor, hamiltonian.ferromagnetic_energy()
(-1.0, -4.5)
>>> hamiltonian.factor = 1
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
-1.0
>>> hamiltonian.factor, hamiltonian.ferromagnetic_energy()
(1.0, -4.5)
>>> hamiltonian.factor = -2
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
0.5
>>> hamiltonian.factor, hamiltonian.ferromagnetic_energy()
(-2.0, -4.5)
>>> hamiltonian.factor = -0.5
>>> hamiltonian[Cr, Cr, (1, 0, 0)].iso
2.0
>>> hamiltonian.factor, hamiltonian.ferromagnetic_energy()
(-0.5, -4.5)

Crystal of the spin Hamiltonian#

SpinHamiltonian is a child of Crystal and inherits all its properties and methods. Any property, which is related to the crystal is expected to be called directly from the SpinHamiltonian instance. For example:

>>> hamiltonian = SpinHamiltonian(lattice=tet_lattice)
>>> hamiltonian.variation
'TET'
>>> hamiltonian.a1
array([3.14159265, 0.        , 0.        ])
>>> hamiltonian.cell
array([[3.14159265, 0.        , 0.        ],
       [0.        , 3.14159265, 0.        ],
       [0.        , 0.        , 4.71238898]])

The crystal of the Spin Hamiltonian can be access through the SpinHamiltonian.crystal attribute. It returns an independent instance of the Crystal class:

>>> hamiltonian = SpinHamiltonian(lattice=tet_lattice)
>>> crystal = hamiltonian.crystal
>>> crystal.cell
array([[3.14159265, 0.        , 0.        ],
       [0.        , 3.14159265, 0.        ],
       [0.        , 0.        , 4.71238898]])
>>> hamiltonian.cell
array([[3.14159265, 0.        , 0.        ],
       [0.        , 3.14159265, 0.        ],
       [0.        , 0.        , 4.71238898]])
>>> crystal.cell = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
>>> crystal.cell
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]])
>>> hamiltonian.cell
array([[3.14159265, 0.        , 0.        ],
       [0.        , 3.14159265, 0.        ],
       [0.        , 0.        , 4.71238898]])