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)