"""Nearest-neighbour spin-S models.
Uniform lattice of spin-S sites, coupled by nearest-neighbour interactions.
"""
# Copyright 2018-2019 TeNPy Developers, GNU GPLv3
import numpy as np
from ..networks.site import SpinSite
from .model import CouplingMPOModel, NearestNeighborModel
from ..tools.params import get_parameter
from ..tools.misc import any_nonzero
__all__ = ['SpinModel', 'SpinChain']
[docs]class SpinModel(CouplingMPOModel):
r"""Spin-S sites coupled by nearest neighbour interactions.
The Hamiltonian reads:
.. math ::
H = \sum_{\langle i,j\rangle, i < j}
(\mathtt{Jx} S^x_i S^x_j + \mathtt{Jy} S^y_i S^y_j + \mathtt{Jz} S^z_i S^z_j
+ \mathtt{muJ} i/2 (S^{-}_i S^{+}_j - S^{+}_i S^{-}_j)) \\
- \sum_i (\mathtt{hx} S^x_i + \mathtt{hy} S^y_i + \mathtt{hz} S^z_i) \\
+ \sum_i (\mathtt{D} (S^z_i)^2 + \mathtt{E} ((S^x_i)^2 - (S^y_i)^2))
Here, :math:`\langle i,j \rangle, i< j` denotes nearest neighbor pairs.
All parameters are collected in a single dictionary `model_params` and read out with
:func:`~tenpy.tools.params.get_parameter`.
Parameters
----------
S : {0.5, 1, 1.5, 2, ...}
The 2S+1 local states range from m = -S, -S+1, ... +S.
conserve : 'best' | 'Sz' | 'parity' | None
What should be conserved. See :class:`~tenpy.networks.Site.SpinSite`.
For ``'best'``, we check the parameters what can be preserved.
Jx, Jy, Jz, hx, hy, hz, muJ, D, E: float | array
Couplings as defined for the Hamiltonian above.
lattice : str | :class:`~tenpy.models.lattice.Lattice`
Instance of a lattice class for the underlaying geometry.
Alternatively a string being the name of one of the Lattices defined in
:mod:`~tenpy.models.lattice`, e.g. ``"Chain", "Square", "HoneyComb", ...``.
bc_MPS : {'finite' | 'infinte'}
MPS boundary conditions along the x-direction.
For 'infinite' boundary conditions, repeat the unit cell in x-direction.
Coupling boundary conditions in x-direction are chosen accordingly.
Only used if `lattice` is a string.
order : string
Ordering of the sites in the MPS, e.g. 'default', 'snake';
see :meth:`~tenpy.models.lattice.Lattice.ordering`.
Only used if `lattice` is a string.
L : int
Lenght of the lattice.
Only used if `lattice` is the name of a 1D Lattice.
Lx, Ly : int
Length of the lattice in x- and y-direction.
Only used if `lattice` is the name of a 2D Lattice.
bc_y : 'ladder' | 'cylinder'
Boundary conditions in y-direction.
Only used if `lattice` is the name of a 2D Lattice.
"""
def __init__(self, model_params):
CouplingMPOModel.__init__(self, model_params)
[docs] def init_sites(self, model_params):
S = get_parameter(model_params, 'S', 0.5, self.name)
conserve = get_parameter(model_params, 'conserve', 'best', self.name)
if conserve == 'best':
# check how much we can conserve
if not any_nonzero(model_params, [('Jx', 'Jy'), 'hx', 'hy', 'E'],
"check Sz conservation"):
conserve = 'Sz'
elif not any_nonzero(model_params, ['hx', 'hy'], "check parity conservation"):
conserve = 'parity'
else:
conserve = None
if self.verbose >= 1.:
print(self.name + ": set conserve to", conserve)
site = SpinSite(S, conserve)
return site
[docs] def init_terms(self, model_params):
Jx = get_parameter(model_params, 'Jx', 1., self.name, True)
Jy = get_parameter(model_params, 'Jy', 1., self.name, True)
Jz = get_parameter(model_params, 'Jz', 1., self.name, True)
hx = get_parameter(model_params, 'hx', 0., self.name, True)
hy = get_parameter(model_params, 'hy', 0., self.name, True)
hz = get_parameter(model_params, 'hz', 0., self.name, True)
D = get_parameter(model_params, 'D', 0., self.name, True)
E = get_parameter(model_params, 'E', 0., self.name, True)
muJ = get_parameter(model_params, 'muJ', 0., self.name, True)
# (u is always 0 as we have only one site in the unit cell)
for u in range(len(self.lat.unit_cell)):
self.add_onsite(-hx, u, 'Sx')
self.add_onsite(-hy, u, 'Sy')
self.add_onsite(-hz, u, 'Sz')
self.add_onsite(D, u, 'Sz Sz')
self.add_onsite(E * 0.5, u, 'Sp Sp')
self.add_onsite(E * 0.5, u, 'Sm Sm')
# Sp = Sx + i Sy, Sm = Sx - i Sy, Sx = (Sp+Sm)/2, Sy = (Sp-Sm)/2i
# Sx.Sx = 0.25 ( Sp.Sm + Sm.Sp + Sp.Sp + Sm.Sm )
# Sy.Sy = 0.25 ( Sp.Sm + Sm.Sp - Sp.Sp - Sm.Sm )
for u1, u2, dx in self.lat.pairs['nearest_neighbors']:
self.add_coupling((Jx + Jy) / 4., u1, 'Sp', u2, 'Sm', dx)
self.add_coupling(np.conj((Jx + Jy) / 4.), u2, 'Sp', u1, 'Sm', -dx) # h.c.
self.add_coupling((Jx - Jy) / 4., u1, 'Sp', u2, 'Sp', dx)
self.add_coupling(np.conj((Jx - Jy) / 4.), u2, 'Sm', u1, 'Sm', -dx) # h.c.
self.add_coupling(Jz, u1, 'Sz', u2, 'Sz', dx)
self.add_coupling(muJ * 0.5j, u1, 'Sm', u2, 'Sp', dx)
self.add_coupling(muJ * -0.5j, u1, 'Sp', u2, 'Sm', dx)
# done
[docs]class SpinChain(SpinModel, NearestNeighborModel):
"""The :class:`SpinModel` on a Chain, suitable for TEBD.
See the :class:`SpinModel` for the documentation of parameters.
"""
def __init__(self, model_params):
model_params.setdefault('lattice', "Chain")
CouplingMPOModel.__init__(self, model_params)