Atoms playground

So far we have learned the basics of ASE and how to work with Atoms and Calculator. In this section, we will get more familiar with Atoms through examples of manipulating Atoms.

[1]:
from ase import Atoms
from ase.build import molecule, bulk

copy

After creating atoms, you can use the copy() method to make a copy of it. The elemental species and coordinates of the atoms, as well as the cells, are copied.

In the following, atoms2 is a copy of H2O with the same coordinate values as atoms.

[2]:
atoms = molecule("H2O")
atoms2 = atoms.copy()

print("atoms :", atoms)
print("pos", atoms.positions)
print()
print("atoms2:", atoms2)
print("pos", atoms2.positions)
atoms : Atoms(symbols='OH2', pbc=False)
pos [[ 0.        0.        0.119262]
 [ 0.        0.763239 -0.477047]
 [ 0.       -0.763239 -0.477047]]

atoms2: Atoms(symbols='OH2', pbc=False)
pos [[ 0.        0.        0.119262]
 [ 0.        0.763239 -0.477047]
 [ 0.       -0.763239 -0.477047]]

Change property

Atoms has various get and set methods. We can change the values of Atoms’ attributes through these methods.

For example, the set_momenta method was used to set the momentum of each atom in the previous section.

Change coordinate values

In the case of a change of coordinate values, you can rewrite atoms.positions directly.

[3]:
atoms = molecule("CH3CHO")
atoms.positions
[3]:
array([[ 1.218055,  0.36124 ,  0.      ],
       [ 0.      ,  0.464133,  0.      ],
       [-0.477241,  1.465295,  0.      ],
       [-0.948102, -0.700138,  0.      ],
       [-0.385946, -1.634236,  0.      ],
       [-1.596321, -0.652475,  0.880946],
       [-1.596321, -0.652475, -0.880946]])
[4]:
from pfcc_extras.visualize.view import view_ngl

view_ngl(atoms, representations=["ball+stick"], w=400, h=300)

Let’s move the 0th O atom from [1.218055, 0.36124, 0.] to [2.0, 0, 0].

You can re-assign atoms.positions directly.

[5]:
# First axis 0 specifies atom index = O
# Second axis with the value 0,1,2 corrensponds to x, y, z axis respectively.
atoms.positions[0] = [2.0, 0, 0]
[6]:
view_ngl(atoms, representations=["ball+stick"], w=400, h=300)

It was confirmed that the O atom moved.

Translation and rotation

Translation and rotation of entire atoms can be done using the translate and rotate methods. The translate method translates all molecules by the same amount given a (3,) xyz vector, and translates n atoms by separate amounts given an (n, 3) vector.

The following example translates all atoms by [1.0, 0, 0].

If you check the coordinate values, you will see that they are translated only in the x-axis direction.

[7]:
atoms.translate([1.0, 0, 0])
atoms.positions
[7]:
array([[ 3.      ,  0.      ,  0.      ],
       [ 1.      ,  0.464133,  0.      ],
       [ 0.522759,  1.465295,  0.      ],
       [ 0.051898, -0.700138,  0.      ],
       [ 0.614054, -1.634236,  0.      ],
       [-0.596321, -0.652475,  0.880946],
       [-0.596321, -0.652475, -0.880946]])

The rotate method is used to rotate atoms.

The following example rotates atoms by 90° along the z-axis. The rotation axis can also be specified as a vector like v=[0,0,1].

[8]:
atoms.rotate(90, v="z")
atoms.positions
[8]:
array([[ 1.8369702e-16,  3.0000000e+00,  0.0000000e+00],
       [-4.6413300e-01,  1.0000000e+00,  0.0000000e+00],
       [-1.4652950e+00,  5.2275900e-01,  0.0000000e+00],
       [ 7.0013800e-01,  5.1898000e-02,  0.0000000e+00],
       [ 1.6342360e+00,  6.1405400e-01,  0.0000000e+00],
       [ 6.5247500e-01, -5.9632100e-01,  8.8094600e-01],
       [ 6.5247500e-01, -5.9632100e-01, -8.8094600e-01]])
[9]:
view_ngl(atoms, representations=["ball+stick"], w=400, h=300)

When a system with a periodic structure is rotated, as shown below, the cell remains unchanged and only the coordinates of the atoms are rotated, so the atoms are out of the cell.

[10]:
atoms = bulk("Fe") * (2, 3, 4)

atoms.rotate(90, v=[0, 0, 1])
view_ngl(atoms, representations=["ball+stick"], w=400, h=300)

To rotate the coordinates of the cell at the same time, use rotate_cell=True.

[11]:
atoms = bulk("Fe") * (2, 3, 4)

atoms.rotate(90, v=[0, 0, 1], rotate_cell=True)
view_ngl(atoms, representations=["ball+stick"], w=400, h=300)

Random move

The rattle method can be used to create a slightly messy structure by randomly moving each atom.

In this example, we first create a Si crystal.

[12]:
atoms = bulk("Si") * (2, 3, 4)
view_ngl(atoms, representations=["ball+stick"], w=400, h=300)

Let’s disturb the structure of this system a little with rattle. The direction of displacement can be changed by changing the seed specification.

[13]:
atoms.rattle(stdev=0.2, seed=1)
view_ngl(atoms, w=400, h=300)

It can also be disturbed to a greater degree by changing the value of stdev.

[14]:
atoms.rattle(stdev=0.5)
view_ngl(atoms, w=400, h=300)

[Note (Advanced)] When the seed argument of the rattle method in ASE is not specified, ``seed=42`` is used, and the result of the rattle is deterministic.

In the following example, the results of the two rattle calls are the same.

[15]:
import numpy as np


atoms = bulk("Si") * (2, 3, 4)
atoms2 = atoms.copy()

atoms.rattle(stdev=0.2)
atoms2.rattle(stdev=0.2)

print("atoms & atoms2 positions are same? --> ", np.allclose(atoms.positions, atoms2.positions))
atoms & atoms2 positions are same? -->  True

If you want to get a different random result each time, specify rng=np.random.RandomState().

[16]:
atoms = bulk("Si") * (2, 3, 4)
atoms2 = atoms.copy()

atoms.rattle(stdev=0.2, rng=np.random.RandomState())
atoms2.rattle(stdev=0.2, rng=np.random.RandomState())

print("atoms & atoms2 positions are same? --> ", np.allclose(atoms.positions, atoms2.positions))
atoms & atoms2 positions are same? -->  False

wrap

If an atom has been moved outside of the cell, as in the Si crystal above, it can be brought back inside the corresponding periodic structure by using the wrap function.

[17]:
atoms.wrap()
view_ngl(atoms, w=400, h=300)