ASE Tutorial 2: Atoms and Unitcell

In this section methods for manipulating atom positions and super cells declarations are discussed.

Manipulating atomic positions

We will end up with a one layer slab with one adatom

Define the slab atoms:

>>> from ASE import Atom, ListOfAtoms
>>> atoms = ListOfAtoms([Atom('Ni', (0, 0, 0)),
...                      Atom('Ni', (0.45, 0, 0)),
...                      Atom('Ni', (0, 0.5, 0)),
...                      Atom('Ni', (0.5, 0.5, 0))])

Have a look at the individual atoms:

>>> atoms[0]
Atom('Ni', (0.0, 0.0, 0.0))
>>> atoms[1]
Atom('Ni', (0.45, 0.0, 0.0))
>>> atoms[2]
Atom('Ni', (0, 0.5, 0.0))
>>> atoms[3]
Atom('Ni', (0.5, 0.5, 0.0))

Let us assume we forgot how many atoms we set up:

>>> atoms[4]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: list index out of range

Change the position of the 2nd atom in the list:

>>> atoms[1].SetCartesianPosition((0.5,0,0))
>>> atoms[1].GetCartesianPosition()
[ 0.5  0.    0.  ]
>>> atoms
[Atom('Ni', (0.0, 0.0, 0.0)),
 Atom('Ni', (0.5, 0.0, 0.0)),
 Atom('Ni', (0, 0.5, 0.0)),
 Atom('Ni', (0.5, 0.5, 0.0))]

What is the unit cell so far?:

>>> atoms.GetUnitCell()
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]

Now, setup a p(2x2) cell in a hexagonal surface a is the fcc lattice constant, the cell is 10 layers high:

>>> from math import sqrt
>>> a=3.55
>>> cell=[(2/sqrt(2.)*a, 0, 0),
...       (1/sqrt(2.)*a, sqrt(3./2.)*a, 0),
...       (0, 0, 10*sqrt(3.)/3.*a)]
>>> cell
(5.0204581464244864, 0, 0),
(2.5102290732122432, 4.3478442934401409, 0),
(0, 0, 20.495934556231713)]
>>> atoms.SetUnitCell(cell)
>>> atoms
[Atom('Ni', (0.0, 0.0, 0.0)),
 Atom('Ni', (2.5102290732122432, 0.0, 0.0)),
 Atom('Ni', (1.2551145366061216, 2.1739221467200704, 0.0)),
 Atom('Ni', (3.7653436098183644, 2.1739221467200704, 0.0))]

Plot the whole system, repeating the slab 2 times in each direction:

>>> from ASE.Visualization.RasMol import RasMol
>>> plot = RasMol(atoms,(2,2,2))
fig1

We now add an adatom. Since the super cell is now declared in our unit cell, we would have to either declare the position of the new atom in Angstroms or to convert back the unit cell

Convert back the unit cell, and add the adatom:

>>> xyzcell=[(1, 0, 0), (0, 1, 0), (0, 0, 1)]
>>> atoms.SetUnitCell(xyzcell)
>>> atoms.append(Atom('Ni', (1/6., 1/6., .1)))

Declare again the unit cell and update the plot:

>>> atoms.SetUnitCell(cell)
>>> plot.Update()
fig2

Manipulating the unitcell

Conventional setup of unit cell:

>>> import Numeric as num
>>> a=3.55
>>> cell=[(2/sqrt(2.)*a, 0, 0),
...      (1/sqrt(2.)*a, sqrt(3./2.)*a, 0),
...      (0, 0, 10*sqrt(3.)/3.*a)]
>>> cell
[(5.0204581464244864, 0, 0),
 (2.5102290732122432, 4.3478442934401409, 0),
 (0, 0, 20.495934556231713)]

Alternative setup of same cell:

>>> cell=num.array([(2/sqrt(2.), 0, 0),
...                 (1/sqrt(2.), sqrt(3./2.), 0),
...                 (0, 0, 10*sqrt(3.)/3.)])
>>> cell=cell*a
>>> cell
[[5.0204581464244864, 0.0, 0.0],
 [2.5102290732122432, 4.3478442934401409, 0.0],
 [0.0, 0.0, 20.495934556231713]]

Now we decide to change the height of the unit cell:

>>> cell[2,2]=cell[2,2]*0.5
>>> cell
[[5.0204581464244864, 0.0, 0.0],
 [2.5102290732122432, 4.3478442934401409, 0.0],
 [0.0, 0.0, 10.247967278115857]]

When changing the super cell, the atoms must now be fixed at their Cartesian coordinates in Angstroms:

>>> atoms[4].GetCartesianPosition()
[ 1.25511454  0.72464072  2.04959346]
>>> atoms.SetUnitCell(cell, fix=True)
>>> atoms[4].GetCartesianPosition()
[ 1.25511454  0.72464072  2.04959346]

If one forgets to fix the atoms, they are stretched with the super cell:

>>> cell[2,2]=cell[2,2]*2
>>> cell
[[5.0204581464244864, 0.0, 0.0],
 [2.5102290732122432, 4.3478442934401409, 0.0],
 [0.0, 0.0, 20.495934556231713]]
>>> atoms[4].GetCartesianPosition()
[ 1.25511454  0.72464072  2.04959346]
>>> atoms.SetUnitCell(cell)
>>> atoms[4].GetCartesianPosition()
[ 1.25511454  0.72464072  4.09918691]