66class UniformExchange (Energy ):
77
88 """
9- The Hamiltonian is defined as
109
11- Hamiltonian = - J \sum_<i,j> S_i \cdot S_j
10+ This class provides the Exchange Interaction energy term for a
11+ homogeneous material, defined as
1212
13- where the brackets represent the nearest neighbours and only evaluate once
14- for each pair, which means for two spins case, the total energy is
15- -J S_1 S_2. Therefore, the effective field at site i is,
13+ __ -> ->
14+ E = - \ J_ij S_i * S_j
15+ /__
16+ <i, j>
17+ i != j
1618
17- H_i = J \sum_<i,j> S_j
19+ where J_ij is the exchange tensor, S_i and S_j are the total spin vectors
20+ at the i-th and j-th lattice sites, and <i, j> means counting the
21+ interaction between neighbouring spins only once (notice that there is no
22+ factor of 2 associated with J)
23+
24+ This class only computes a uniform exchange field, thus J_ij is a
25+ diagonal tensor with constant magnitude, J_ij -> J
26+
27+
28+ OPTIONAL ARGUMENTS: -------------------------------------------------------
29+
30+ J :: A number for the exchange tensor magnitude
31+ name :: Interaction name
32+
33+ USAGE: --------------------------------------------------------------------
34+
35+ For a homogeneous material, it can be specified in a simulation object
36+ *Sim* as
37+
38+ Sim.add(UniformExchange(J))
39+
40+ where J is a float.
1841
19- notice that there is no factor of 2 associated with J.
2042 """
2143
2244 def __init__ (self , J = 0 , name = 'exch' ):
@@ -64,42 +86,84 @@ def compute_energy_directly(self):
6486class Exchange (Energy ):
6587
6688 """
67- The Hamiltonian is defined as
89+ This class provides the Exchange Interaction energy term, defined as
90+
91+ __ -> ->
92+ E = - \ J_ij S_i * S_j
93+ /__
94+ <i, j>
95+ i != j
96+
97+ where J_ij is the exchange tensor, S_i and S_j are the total spin vectors
98+ at the i-th and j-th lattice sites, and <i, j> means counting the
99+ interaction between neighbouring spins only once (notice that there is no
100+ factor of 2 associated with J)
101+
102+ In general, J_ij is space dependent and must be specified for every
103+ neighbour. For a homogeneous material, J_ij is a diagonal tensor with
104+ constant magnitude, i.e. J_ij -> J.
105+
106+
107+ OPTIONAL ARGUMENTS: -------------------------------------------------------
108+
109+ J_fun :: The exchange tensor which can be a number (same
110+ magnitude for every neighbour at every lattice site)
111+ or a space dependent function that returns 6
112+ components, one for every nearest neighbour (NN).
113+ For a square lattice the NNs are defined in 3D as:
114+ [-x +x -y +y -z +z], thus the exchange components
115+ are specified in that order. In a hexagonal lattice
116+ the NNs are only in a 2D plane as the cardinal
117+ positions: [W E NE SW NW SE].
68118
69- Hamiltonian = - \sum_<i,j> J_ij S_i \cdot S_j
119+ name :: Interaction name
70120
71- where the brackets represent the nearest neighbours and only evaluate once
72- for each pair, which means for two spins case, the total energy is
73- -J S_1 S_2. Therefore, the effective field at site i is,
121+ USAGE: --------------------------------------------------------------------
122+
123+ For a homogeneous material, it can be specified in a simulation object
124+ *Sim* as
125+
126+ Sim.add(Exchange(J))
127+
128+ where J is a float.
129+
130+ Otherwise, the exchange tensor is spatial dependent, and must be specified
131+ using a function. For a cubic mesh, for example, if we want a linear
132+ dependence only with in plane components:
133+
134+ def my_exchange(pos):
135+ J = 1 * meV
136+ x, y, z = pos[0], pos[1], pos[2]
137+
138+ return (x * J, x * J, y * J, y * J, 0, 0)
139+
140+ Sim.add(Exchange(my_exchange))
74141
75- H_i = \sum_<i,j> J_ij S_j
76142
77- notice that there is no factor of 2 associated with J_ij.
78143 """
79144
80145 def __init__ (self , J_fun , name = 'exch' ):
81146 self .J_fun = J_fun
82147 self .name = name
83148 self .jac = False
84-
149+
85150 def setup (self , mesh , spin , mu_s ):
86151 super (Exchange , self ).setup (mesh , spin , mu_s )
87152
88153 self ._J = np .zeros (self .neighbours .shape )
89154
90155 if isinstance (self .J_fun , (int , float )):
91- self ._J [:,:] = self .J_fun
156+ self ._J [:, :] = self .J_fun
92157 elif hasattr (self .J_fun , '__call__' ):
93- n = self .mesh .n
158+ n = self .mesh .n
94159 for i in range (n ):
95160 value = self .J_fun (self .coordinates [i ])
96161 if len (value ) == 6 :
97- self ._J [i ,:] = value [:]
162+ self ._J [i , :] = value [:]
98163 else :
99164 raise Exception ('The given spatial function for J is not acceptable!' )
100165 pass
101-
102-
166+
103167 def compute_field (self , t = 0 , spin = None ):
104168
105169 if spin is not None :
@@ -108,10 +172,10 @@ def compute_field(self, t=0, spin=None):
108172 m = self .spin
109173
110174 clib .compute_exchange_field_spatial (m ,
111- self .field ,
112- self .energy ,
113- self ._J ,
114- self .neighbours ,
115- self .n )
175+ self .field ,
176+ self .energy ,
177+ self ._J ,
178+ self .neighbours ,
179+ self .n )
116180
117181 return self .field * self .mu_s_inv
0 commit comments