Internal data structure of SpinW

Import the LiCrO2 crystal structure from a web link. It has space group R-3m, rhombohedrl crystal structure in hexagonal settings. What is the density? Where does all the data comes from? edit atom.dat

Contents

Get the lattice

licro = spinw('https://raw.githubusercontent.com/SpinW/Models/master/cif/licro2.cif');

licro.formula
     Chemical formula:  Cr1Li1O2
     Formula mass:        90.936 g/mol
     Formula in cell:          3 units
     Cell volume:        105.178 ų
     Density:              4.307 g/cm³

Check out internal data structure of SpinW

What do you see?

properties(spinw)

licro.lattice
Properties for class spinw:

    lattice
    unit_cell
    twin
    matrix
    single_ion
    coupling
    mag_str
    unit
    cache


ans = 

  struct with fields:

        angle: [1.5708 1.5708 2.0944]
    lat_const: [2.9010 2.9010 14.4311]
          sym: [3×4×36 double]
       origin: [0 0 0]
        label: 'R -3 m H'

Test cordinate transformations

Convert (1,1,0) in the reciprocal lattice of LiCrO2 to A^-1 and convert (1,0,0) in lattice units to the crystal Descartes coordinate system (denoted by xyz in SpinW).

How are Trl and Tr related?

Trl = licro.rl;
Q = [0 1 0];
QinvA = Q*Trl

Tl = licro.basisvector;
pos = [1;0;0];
RA = Tl*pos
QinvA =

         0    2.5009   -0.0000


RA =

    2.9010
         0
         0

Rotate a vector

Using the rotation axis and Rotation angle in degree, the sw_rotmatd can generate the corresponding rotation matrix.

R = sw_rotmatd([0 0 1],60);

% Rotate polar vector
R*pos
ans =

    0.5000
    0.8660
         0

Magnetic atoms

Can you find the magnetic atom positions on the plot and connect them to the list in mAtom and in licro.unit_cell?

plot(licro)
mAtom = licro.matom
mAtom = 

  struct with fields:

      r: [3×3 double]
    idx: [2 2 2]
      S: [1.5000 1.5000 1.5000]

Space groups

Check out symmetry.dat: What does it mean P0~=P1? In case P0 the equivalent bonds are determined based on length, while for P1 (or any other space group), the equivalent bonds are determined based on the symmetry operators.

edit symmetry.dat

Bond symmetry

Generate the bond list of LiCrO2. Are the bonds generated usign the space group? What does it mean?

licro.gencoupling

% The first neighbor bonds
licro.table('bond',1)
ans =

  9×10 table

    idx    subidx          dl                dr          length      matom1      idx1      matom2      idx2        matrix    
    ___    ______    ______________    ______________    ______    __________    ____    __________    ____    ______________

     1       1       -1    -1     0    -1    -1     0    2.901     'Cr1 Cr3+'     2      'Cr1 Cr3+'     2      ''    ''    ''
     1       2        0     1     0     0     1     0    2.901     'Cr1 Cr3+'     2      'Cr1 Cr3+'     2      ''    ''    ''
     1       3        1     0     0     1     0     0    2.901     'Cr1 Cr3+'     2      'Cr1 Cr3+'     2      ''    ''    ''
     1       4        1     1     0     1     1     0    2.901     'Cr1 Cr3+'     3      'Cr1 Cr3+'     3      ''    ''    ''
     1       5        0    -1     0     0    -1     0    2.901     'Cr1 Cr3+'     3      'Cr1 Cr3+'     3      ''    ''    ''
     1       6       -1     0     0    -1     0     0    2.901     'Cr1 Cr3+'     3      'Cr1 Cr3+'     3      ''    ''    ''
     1       7        1     1     0     1     1     0    2.901     'Cr1 Cr3+'     1      'Cr1 Cr3+'     1      ''    ''    ''
     1       8        0    -1     0     0    -1     0    2.901     'Cr1 Cr3+'     1      'Cr1 Cr3+'     1      ''    ''    ''
     1       9       -1     0     0    -1     0     0    2.901     'Cr1 Cr3+'     1      'Cr1 Cr3+'     1      ''    ''    ''

Lets do something crazy

Lets convert the hexagonal cell to the primitive cell and see what happens.

Why copy()? The spinw object is handle object, the copy() command creates a hard copy to avoid modifying the original object. Check spinw.formula() to see how much the new cell is smaller

licroR = copy(licro);
T = licroR.newcell('bvect',{[-1 1 1]/3 [2 1 1]/3 [-1 -2 1]/3})
plot(licroR,'cellMode','outside')
swplot.zoom(1.5)
T =

   -0.3333    0.3333    0.3333
    0.6667    0.3333    0.3333
   -0.3333   -0.6667    0.3333

Lets add a few matrices

What does the different input do? Check the result by inspecting the licro.matrix.mat array.

licro.addmatrix('label','J','value',1)
licro.addmatrix('label','D','value',[0 1 0])
licro.addmatrix('label','A','value',diag([1 0.5 0.5]))

Lets add some matrices and plot

Do both for the primitive and the hexagonal cell Are they the same?

licroR.gencoupling
licroR.addmatrix('label','J','value',1)
licroR.addcoupling('bond',1,'mat','J')
plot(licroR,'range',[3 3 3],'unit','lu','atomMode','mag','cellMode','none','atomLegend',false)
swplot.zoom(1.5)

Plot a single triangular layer from LiCrO2

licro.addcoupling('bond',1,'mat','J')
plot(licro,'range',[15 15 5],'unit','xyz','atomMode','mag','cellMode','none','atomLegend',false)

Single ion properties

Assing the A matrix to single ion anisotropy.

licro.addaniso('A')
plot(licro)

Magnetic structure

Lets start with a simpler lattice: square lattice. Define a (1/2,1/2,0) magnetic structure using complex magnetization vectors.

What does [1-1i;1+1i;0] vector means? These are the complex magnetization vectors. SpinW 3.0 stores complex magnetization vectors internally and generates the real magnetic structure on the fly.

How is this stored in the spinw object? check spinw.mag_str and check spinw.magstr for the generated real structure.

Let's create a magnetic supercell! 2x2x1 cell What will be the k-vector now? (1/2,1/2,0) or (1,1,0)? They are indeed equivalent.

To check that we are doing the right thing, we will keep track of the enrgy of the system, after adding a J=1 meV Heisenberg exchange on the square lattice. To create Heisenberg Hamiltonian quickly we use square.quickham(1.25), to create the first neighbor bonds with J=1.25 meV.

What was the energy/spin for the original magnetic structure? S=1, J = 1.25 meV?

square = sw_model('squareAF');
plot(square,'range',[2 2 1/2])

square.genmagstr('mode','direct','S',[1-1i;1+1i;0],'k',[1/2 1/2 0],'nExt',[1 1 1])
plot(square,'range',[2 2 1/2])

square.quickham(1)

square.energy

% Create supercell, which k-vector is right? k is always in the units of
% the crystal reciprocal lattice!

square.genmagstr('mode','direct','S',[1 -1 -1 1;0 0 0 0;0 0 0 0],'nExt',[2 2 1],'k',[0 0 0])
square.energy

square.genmagstr('mode','direct','S',[1 -1 -1 1;0 0 0 0;0 0 0 0],'nExt',[2 2 1],'k',[1/2 1/2 0])
square.energy
Ground state energy: -2.000 meV/spin.
Ground state energy: -2.000 meV/spin.
Ground state energy: -2.000 meV/spin.

Rotating frame representation

Let's generate a spiral using the J1-J2 model of a zig-zag chain. Check the spinw.mag_str and spinw.magstr and compare them.

ch = spinw;
ch.genlattice('lat_const',[3 5 4])
ch.addatom('r',[0 .3 0],'S',1)
ch.addatom('r',[1/2 0.7 0],'S',1)
ch.quickham([1 1/2])

ch.optmagk
ch.optmagsteep
ch.energy

plot(ch,'range',[5 1 1/2])
ans = 

  struct with fields:

       k: [3×1 double]
       E: -0.7500
       F: [3×2 double]
    stat: [1×1 struct]

Warning: Some spins are coupled to themselves in the present magnetic cell! 
Ground state energy: -0.750 meV/spin.

Let's do some animation by rotating the moments

for ii = 1:100
    ch.genmagstr('mode','rotate','n',[0 0 1],'phid',1)
    swplot.plotmag('range',[5 1 1/2])
    drawnow
end

Check the spin wave dispersion

spec = ch.spinwave({[0 0 0] [1 0 0] 501});
spec = sw_egrid(spec);
spec = sw_instrument(spec,'dE',0.1);
figure
sw_plotspec(spec,'mode','color')
legend off

% Plot the neutron scattering cross section per spin wave mode.
figure
spec = sw_omegasum(spec,'zeroint',1e-5,'tol',1e-3);
sw_plotspec(spec,'mode','int','axLim',[0 5],'colormap',[0 0 0])
Warning: To make the Hamiltonian positive definite, a small omega_tol value was
added to its diagonal! 

Case when the rotating frame representation fails

We show here what happens when there are counterrotating spirals.

ch = spinw;
ch.genlattice('lat_const',[3 7 4])
ch.addatom('r',[1/2 1/4 0],'S',1)
ch.addatom('r',[1/2 3/4 0],'S',1)
ch.addmatrix('label','DM1','value',[0  1 0])
ch.addmatrix('label','DM2','value',[0 -1 0])

ch.gencoupling
ch.addcoupling('mat','DM1','bond',1,'subIdx',1)
ch.addcoupling('mat','DM2','bond',1,'subIdx',2)

optRes = ch.optmagk;
plot(ch,'range',[5 1 1/2])

% Rotating frame representation fails!
ch.magstr

% Lets check how the structure would look like in a magnetic supercell.
ch.magstr('nExt',[4 1 1])

% Let's generate this supercell and keep it.
ch.genmagstr('mode','helical','nExt',[4 1 1])

% Let's check the energy if we are right, -1 meV/spin looks fine.
ch.energy
Warning: Convergence is not reached! 
Warning: The stored magnetic structure does not have an exact representation in
the rotating frame formalism! 

ans = 

  struct with fields:

        S: [3×2 double]
        k: [0.7501 0 0]
        n: [0 1 0]
    N_ext: [1 1 1]
    exact: 0

Warning: The stored magnetic structure does not have an exact representation in
the rotating frame formalism! 

ans = 

  struct with fields:

        S: [3×8 double]
        k: [0.7501 0 0]
        n: [0 1 0]
    N_ext: [4 1 1]
    exact: 0

Warning: In the extended unit cell k is still larger than epsilon! 
Warning: The stored magnetic structure does not have an exact representation in
the rotating frame formalism! 
Ground state energy: -1.000 meV/spin.