/
spins.py
106 lines (88 loc) · 4.16 KB
/
spins.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"""Nearest-neighbour spin-S models.
Uniform lattice of spin-S sites, coupled by nearest-neighbour interactions.
"""
# Copyright 2018-2020 TeNPy Developers, GNU GPLv3
import numpy as np
from ..networks.site import SpinSite
from .model import CouplingMPOModel, NearestNeighborModel
from ..tools.params import asConfig
__all__ = ['SpinModel', 'SpinChain']
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`, which
is turned into a :class:`~tenpy.tools.params.Config` object.
Parameters
----------
model_params : :class:`~tenpy.tools.params.Config`
Parameters for the model. See :cfg:config:`SpinModel` below.
Options
-------
.. cfg:config :: SpinModel
:include: CouplingMPOModel
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
Coupling as defined for the Hamiltonian above.
"""
def init_sites(self, model_params):
S = model_params.get('S', 0.5)
conserve = model_params.get('conserve', 'best')
if conserve == 'best':
# check how much we can conserve
if not model_params.any_nonzero([('Jx', 'Jy'), 'hx', 'hy', 'E'],
"check Sz conservation"):
conserve = 'Sz'
elif not model_params.any_nonzero(['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
def init_terms(self, model_params):
Jx = model_params.get('Jx', 1.)
Jy = model_params.get('Jy', 1.)
Jz = model_params.get('Jz', 1.)
hx = model_params.get('hx', 0.)
hy = model_params.get('hy', 0.)
hz = model_params.get('hz', 0.)
D = model_params.get('D', 0.)
E = model_params.get('E', 0.)
muJ = model_params.get('muJ', 0.)
# (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, plus_hc=True)
self.add_coupling((Jx - Jy) / 4., u1, 'Sp', u2, 'Sp', dx, plus_hc=True)
self.add_coupling(Jz, u1, 'Sz', u2, 'Sz', dx)
self.add_coupling(muJ * 0.5j, u1, 'Sm', u2, 'Sp', dx, plus_hc=True)
# done
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 = asConfig(model_params, self.__class__.__name__)
model_params.setdefault('lattice', "Chain")
CouplingMPOModel.__init__(self, model_params)