Atomsの操作

ここまででASEの基礎を学び Atoms や Calculatorの扱い方を学びました。 本節では、Atomsを操作していく実例を通してその扱いにより深く慣れていきましょう。

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

コピー

atomsを作成したあと、そのコピーを作成するには copy() methodを使うことができます。 原子の元素種・座標値や、セルなどがコピーされます。

以下ではatoms2atomsと同じ座標値を持ったH2Oのコピーになっています。

[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]]

propertyの書き換え

Atomsは様々なget, set 関数を持っています。これらを通じてAtomsの持つ属性値を変更することが可能です。

例えば前節では set_momenta 関数を使用して運動量を設定する例がありました。

座標値の変更

座標値の変更の場合、atoms.positions をそのまま書き換えることができます。

[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)

0番目のO原子を [1.218055, 0.36124, 0.] から、 [2.0, 0, 0] に動かしてみます。

atoms.positions をそのまま書き換えることができます。

[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)

O原子が動いたことが確認できました。

平行移動、回転

atoms全体の平行移動や回転は、translate, rotate 関数を使うことができます。

translate関数は (3,) のxyzベクトルを指定するとすべての分子を同じだけ平行移動し、 (n, 3) のベクトルを指定するとn個の原子を別々の量平行移動します。 以下の例では、すべての原子を [1.0, 0, 0] 平行移動しています。 実際に座標値を見ると x軸方向だけ平行移動されているのがわかります。

[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]])

rotate関数は atomsを回転させるための関数です。

以下の例は z軸方向を回転軸として 90°回転させています。 回転軸は、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)

周期構造を持つ系を回転させた場合、以下のように、Cellはそのままで原子の座標のみが回転されるため、原子は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)

Cellの座標も同時に回転させるには、 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)

ランダム移動

rattle 関数を使うと、それぞれの原子をランダム移動させて少し乱雑な構造を作成することができます。

ここでは、まずSi 結晶を作成します。

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

この系を rattle で少し構造を乱してみます。変位の方向はseedの指定を変えることで、変えることができます。

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

stdevの値を変えることでより大きく乱す事もできます。

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

[Note (Advanced)] ASEのrattle 関数の引数であるseed が指定されていないときは ``seed=42`` が使われるという仕様になっており、結果``rattle``の結果はDeterministicになるので注意してください。

以下の例では、2回 rattleを行った結果が等しくなっていることを確認しています。

[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

もし、毎回違う結果をランダムに得たい場合は 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

上記のSi結晶のように、Cellの外側に原子が飛び出してしまった場合、 wrap 関数を使うことで再び対応する周期構造の内側に戻す事ができます。

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