Introduction to atomman: Point defect generation

Lucas M. Hale, lucas.hale@nist.gov, Materials Science and Engineering Division, NIST.

Disclaimers

1. Introduction

This Notebook provides an introduction to tools in atomman for generating point defects.

Library Imports

[1]:
# Standard libraries
import datetime

# http://www.numpy.org/
import numpy as np

# https://github.com/usnistgov/atomman
import atomman as am
import atomman.unitconvert as uc

# Show atomman version
print('atomman version =', am.__version__)

# Show date of Notebook execution
print('Notebook executed on', datetime.date.today())
atomman version = 1.4.10
Notebook executed on 2023-07-28

Define 2x2x2 CsCl supercell for testing

[2]:
atoms = am.Atoms(atype=[1,2], pos=[[0.0, 0.0, 0.0],[0.5, 0.5, 0.5]], charge=[-1.0, 1.0])
alat = uc.set_in_units(4.11, 'angstrom')
box = am.Box(a=alat, b=alat, c=alat)
ucell = am.System(atoms=atoms, box=box, scale=True)
system = ucell.supersize(2,2,2)

# Print system information
print(system.box)
print('natoms =', system.natoms)
print('natypes =', system.natypes)
system.atoms_df()
avect =  [ 8.220,  0.000,  0.000]
bvect =  [ 0.000,  8.220,  0.000]
cvect =  [ 0.000,  0.000,  8.220]
origin = [ 0.000,  0.000,  0.000]
natoms = 16
natypes = 2
[2]:
atype pos[0] pos[1] pos[2] charge
0 1 0.000 0.000 0.000 -1.0
1 2 2.055 2.055 2.055 1.0
2 1 4.110 0.000 0.000 -1.0
3 2 6.165 2.055 2.055 1.0
4 1 0.000 4.110 0.000 -1.0
5 2 2.055 6.165 2.055 1.0
6 1 4.110 4.110 0.000 -1.0
7 2 6.165 6.165 2.055 1.0
8 1 0.000 0.000 4.110 -1.0
9 2 2.055 2.055 6.165 1.0
10 1 4.110 0.000 4.110 -1.0
11 2 6.165 2.055 6.165 1.0
12 1 0.000 4.110 4.110 -1.0
13 2 2.055 6.165 6.165 1.0
14 1 4.110 4.110 4.110 -1.0
15 2 6.165 6.165 6.165 1.0
[3]:
am.plot.py3Dmol.view_3d(system, height=400, width=400)

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
jupyter labextension install jupyterlab_3dmol

2. atomman.defect.vacancy()

Generates a new system by adding a vacancy point defect.

  1. Removes the indicated atom from the system

  2. Adds per-atom property old_id if it doesn’t exist corresponding to the atom ids in the original system.

Parameters

  • system (atomman.System) The base System to add the defect to.

  • pos (array-like object, optional) Position of the atom to be removed. Either pos or ptd_id must be given.

  • ptd_id (int, optional) Id of the atom to be removed. Either pos or ptd_id must be given.

  • scale (bool, optional) Indicates if pos is Cartesian (False) or box-relative (True). Default value is False.

  • atol (float, optional) Absolute tolerance for position-based searching. Default value is 1e-3 angstroms.

Returns

  • (atomman.System) A new system with the vacancy added.

[4]:
# Add a vacancy by deleting atom 5
d_system = am.defect.vacancy(system, ptd_id=5)

# Add a second vacancy by deleting atom at position [0.00, 4.110, 4.110]
d_system = am.defect.vacancy(d_system, pos=[0.00, 4.11, 4.11])

# Print system information
print(d_system.box)
print('natoms =', d_system.natoms)
print('natypes =', d_system.natypes)
d_system.atoms_df()
avect =  [ 8.220,  0.000,  0.000]
bvect =  [ 0.000,  8.220,  0.000]
cvect =  [ 0.000,  0.000,  8.220]
origin = [ 0.000,  0.000,  0.000]
natoms = 14
natypes = 2
[4]:
atype pos[0] pos[1] pos[2] charge old_id
0 1 0.000 0.000 0.000 -1.0 0
1 2 2.055 2.055 2.055 1.0 1
2 1 4.110 0.000 0.000 -1.0 2
3 2 6.165 2.055 2.055 1.0 3
4 1 0.000 4.110 0.000 -1.0 4
5 1 4.110 4.110 0.000 -1.0 6
6 2 6.165 6.165 2.055 1.0 7
7 1 0.000 0.000 4.110 -1.0 8
8 2 2.055 2.055 6.165 1.0 9
9 1 4.110 0.000 4.110 -1.0 10
10 2 6.165 2.055 6.165 1.0 11
11 2 2.055 6.165 6.165 1.0 13
12 1 4.110 4.110 4.110 -1.0 14
13 2 6.165 6.165 6.165 1.0 15
[5]:
am.plot.py3Dmol.view_3d(d_system, height=400, width=400)

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
jupyter labextension install jupyterlab_3dmol

3. atomman.defect.interstitial()

Generates a new system by adding a vacancy point defect.

  1. Adds a new atom to the end of the Atoms list.

  2. Adds per-atom property old_id if it doesn’t exist corresponding to the atom ids in the original system.

  3. Sets any of the new atom’s per-atom properties to values given as kwargs. Any undefined properties are given zero values except atype, which is set to 1.

Parameters

  • system (atomman.System) The base System to add the defect to.

  • pos (array-like object) Position of the atom being added.

  • scale (bool, optional) Indicates if pos is Cartesian (False) or box-relative (True). Default value is False.

  • atol (float, optional) Absolute tolerance for position-based searching. Default value is 1e-3 angstroms.

  • **kwargs (any, optional) Keyword arguments corresponding to per-atom property values for the new atom. By default, atype==1 and all other properties are set to be all zeros for the property’s shape.

Returns

  • (atomman.System) A new system with the interstitial added.

[6]:
# Add interstitial at pos = [1.515, 1.515, 0.000] without defining atype, charge
d_system = am.defect.interstitial(system, pos=[1.515, 1.515, 0.0])

# Add second interstitial at pos = [1.515, 4.545, 0.000] with defining atype, charge
d_system = am.defect.interstitial(d_system, pos=[1.515, 4.545, 0.0], atype=2, charge=1)

# Print system information
print(d_system.box)
print('natoms =', d_system.natoms)
print('natypes =', d_system.natypes)
d_system.atoms_df()
avect =  [ 8.220,  0.000,  0.000]
bvect =  [ 0.000,  8.220,  0.000]
cvect =  [ 0.000,  0.000,  8.220]
origin = [ 0.000,  0.000,  0.000]
natoms = 18
natypes = 2
[6]:
atype pos[0] pos[1] pos[2] charge old_id
0 1 0.000 0.000 0.000 -1.0 0
1 2 2.055 2.055 2.055 1.0 1
2 1 4.110 0.000 0.000 -1.0 2
3 2 6.165 2.055 2.055 1.0 3
4 1 0.000 4.110 0.000 -1.0 4
5 2 2.055 6.165 2.055 1.0 5
6 1 4.110 4.110 0.000 -1.0 6
7 2 6.165 6.165 2.055 1.0 7
8 1 0.000 0.000 4.110 -1.0 8
9 2 2.055 2.055 6.165 1.0 9
10 1 4.110 0.000 4.110 -1.0 10
11 2 6.165 2.055 6.165 1.0 11
12 1 0.000 4.110 4.110 -1.0 12
13 2 2.055 6.165 6.165 1.0 13
14 1 4.110 4.110 4.110 -1.0 14
15 2 6.165 6.165 6.165 1.0 15
16 1 1.515 1.515 0.000 0.0 16
17 2 1.515 4.545 0.000 1.0 17
[8]:
am.plot.py3Dmol.view_3d(d_system, height=400, width=400)

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
jupyter labextension install jupyterlab_3dmol

4. atomman.defect.substitutional()

Generates a new system by adding a substitutional point defect.

  1. Moves the indicated atom to the end of the list and changes its atype to the value given.

  2. Adds per-atom property old_id if it doesn’t exist corresponding to the atom ids in the original system.

  3. Sets any of the moved atom’s per-atom properties to values given as kwargs. Any undefined properties are left unchanged.

Parameters

  • system (atomman.System) The base System to add the defect to.

  • pos (array-like object, optional) Position of the atom being modified. Either pos or ptd_id must be given.

  • ptd_id (int, optional) Id of the atom to be modified. Either pos or ptd_id must be given.

  • atype (int, optional) Integer atomic type to change the identified atom to. Must be different than the atom’s current id. Default value is 1.

  • scale (bool, optional) Indicates if pos is Cartesian (False) or box-relative (True). Default value is False.

  • atol (float, optional) Absolute tolerance for position-based searching. Default value is 1e-3 angstroms.

  • **kwargs (any, optional) Keyword arguments corresponding to per-atom property values for the modified atom. By default, all properties (except atype) are left unchanged.

Returns

  • (atomman.System) A new system with the substitutional added.

[9]:
# Make atom 1 a substitutional without changing charge
d_system = am.defect.substitutional(system, ptd_id=1, atype=3)

# Add second substitutional at pos = [0.00, 4.11, 4.11] and change charge
d_system = am.defect.substitutional(d_system, pos=[0.00, 4.11, 4.11], atype=2, charge=1)

# Print system information
print(d_system.box)
print('natoms =', d_system.natoms)
print('natypes =', d_system.natypes)
d_system.atoms_df()
avect =  [ 8.220,  0.000,  0.000]
bvect =  [ 0.000,  8.220,  0.000]
cvect =  [ 0.000,  0.000,  8.220]
origin = [ 0.000,  0.000,  0.000]
natoms = 16
natypes = 3
[9]:
atype pos[0] pos[1] pos[2] charge old_id
0 1 0.000 0.000 0.000 -1.0 0
1 1 4.110 0.000 0.000 -1.0 2
2 2 6.165 2.055 2.055 1.0 3
3 1 0.000 4.110 0.000 -1.0 4
4 2 2.055 6.165 2.055 1.0 5
5 1 4.110 4.110 0.000 -1.0 6
6 2 6.165 6.165 2.055 1.0 7
7 1 0.000 0.000 4.110 -1.0 8
8 2 2.055 2.055 6.165 1.0 9
9 1 4.110 0.000 4.110 -1.0 10
10 2 6.165 2.055 6.165 1.0 11
11 2 2.055 6.165 6.165 1.0 13
12 1 4.110 4.110 4.110 -1.0 14
13 2 6.165 6.165 6.165 1.0 15
14 3 2.055 2.055 2.055 1.0 1
15 2 0.000 4.110 4.110 1.0 12
[10]:
am.plot.py3Dmol.view_3d(d_system, height=400, width=400)

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
jupyter labextension install jupyterlab_3dmol

5. atomman.defect.dumbbell()

Generates a new system by adding a dumbbell interstitial point defect.

  1. Copies the indicated atom and moves both the original and copy to the end of the Atoms list.

  2. Displaces the dumbbell atoms position’s by +-db_vect.

  3. Adds per-atom property old_id if it doesn’t exist corresponding to the atom ids in the original system.

  4. Sets any of the new atom’s per-atom properties to values given as kwargs. Any undefined properties are left unchanged.

Parameters

  • system (atomman.System) The base System to add the defect to.

  • pos (array-like object, optional) Position of the atom being modified. Either pos or ptd_id must be given.

  • ptd_id (int, optional) Id of the atom to be modified. Either pos or ptd_id must be given.

  • db_vect (array-like object) Vector shift to apply to the atoms in the dumbbell.

  • scale (bool, optional) Indicates if pos and db_vect are Cartesian (False) or box-relative (True). Default value is False.

  • atol (float, optional) Absolute tolerance for position-based searching. Default value is 1e-3 angstroms.

  • **kwargs (any, optional) Keyword arguments corresponding to per-atom property values for the new atom in the dumbbell. By default, all properties are left unchanged (i.e. same as atom that was copied).

Returns

  • (atomman.System) A new system with the dumbbell added.

[11]:
# Turn atom 5 into a dumbbell
d_system = am.defect.dumbbell(system, ptd_id=5, db_vect=[0.5, 0.5, 0.5])

# Print system information
print(d_system.box)
print('natoms =', d_system.natoms)
print('natypes =', d_system.natypes)
d_system.atoms_df()
avect =  [ 8.220,  0.000,  0.000]
bvect =  [ 0.000,  8.220,  0.000]
cvect =  [ 0.000,  0.000,  8.220]
origin = [ 0.000,  0.000,  0.000]
natoms = 17
natypes = 2
[11]:
atype pos[0] pos[1] pos[2] charge old_id
0 1 0.000 0.000 0.000 -1.0 0
1 2 2.055 2.055 2.055 1.0 1
2 1 4.110 0.000 0.000 -1.0 2
3 2 6.165 2.055 2.055 1.0 3
4 1 0.000 4.110 0.000 -1.0 4
5 1 4.110 4.110 0.000 -1.0 6
6 2 6.165 6.165 2.055 1.0 7
7 1 0.000 0.000 4.110 -1.0 8
8 2 2.055 2.055 6.165 1.0 9
9 1 4.110 0.000 4.110 -1.0 10
10 2 6.165 2.055 6.165 1.0 11
11 1 0.000 4.110 4.110 -1.0 12
12 2 2.055 6.165 6.165 1.0 13
13 1 4.110 4.110 4.110 -1.0 14
14 2 6.165 6.165 6.165 1.0 15
15 2 1.555 5.665 1.555 1.0 5
16 2 2.555 6.665 2.555 1.0 16
[12]:
# Show that dumbbell atoms are separated by 2 * db_vect
print("(d_system.atoms.pos[-1] - d_system.atoms.pos[-2]) / 2 ->", (d_system.atoms.pos[-1] - d_system.atoms.pos[-2]) / 2)
(d_system.atoms.pos[-1] - d_system.atoms.pos[-2]) / 2 -> [0.5 0.5 0.5]
[13]:
am.plot.py3Dmol.view_3d(d_system, height=400, width=400)

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
jupyter labextension install jupyterlab_3dmol

6. atomman.defect.point()

Generates a new System where a point defect has been inserted. Provides a common interface for the vacancy(), interstitial(), substitutional() and dumbbell() functions.

Parameters

  • system (atomman.System) The base System to add the defect to.

  • ptd_type (str, optional) Key indicating which type of defect to add. Default value is ‘v’:

    • ‘v’ : vacancy.

    • ‘i’ : positional interstitial.

    • ‘s’ : substitutional.

    • ‘db’ : dumbbell interstitial.

  • pos (array-like object, optional) Position for adding the defect atom (all styles).

  • ptd_id (int, optional) Atom id where defect is added. Alternative to using pos (‘v’, ‘s’, ‘db’ styles).

  • db_vect (array-like object, optional) Vector associated with the dumbbell interstitial (‘db’ style).

  • scale (bool, optional) Indicates if pos and db_vect are Cartesian (False) or box-relative (True). Default value is False.

  • atol (float, optional) Absolute tolerance for position-based searching. Default value is 1e-3 angstroms.

  • **kwargs (any, optional) Keyword arguments corresponding to per-atom property values for the new/modified atom (‘i’, ‘s’, ‘db’ styles).

Raises

  • (AssertionError) If parameters are given for styles that don’t allow them.

  • (ValueError) If an invalid ptd_type is given.

Returns

  • (atomman.System) A new system containing the defect.

[14]:
# Use point() to make atom 7 a dumbbell of two atoms of atype 3

# ptd_type 's' changes atom 7 and moves to last atom
d_system = am.defect.point(system, 's', ptd_id=7, atype=3, charge=-0.5)

# ptd_type 'db' turns last atom into dumbbell, copying per-atom properties
d_system = am.defect.point(d_system, 'db', ptd_id=-1, db_vect=[0.6, 0.0, 0.6])

# Print system information
print(d_system.box)
print('natoms =', d_system.natoms)
print('natypes =', d_system.natypes)
d_system.atoms_df()
avect =  [ 8.220,  0.000,  0.000]
bvect =  [ 0.000,  8.220,  0.000]
cvect =  [ 0.000,  0.000,  8.220]
origin = [ 0.000,  0.000,  0.000]
natoms = 17
natypes = 3
[14]:
atype pos[0] pos[1] pos[2] charge old_id
0 1 0.000 0.000 0.000 -1.0 0
1 2 2.055 2.055 2.055 1.0 1
2 1 4.110 0.000 0.000 -1.0 2
3 2 6.165 2.055 2.055 1.0 3
4 1 0.000 4.110 0.000 -1.0 4
5 2 2.055 6.165 2.055 1.0 5
6 1 4.110 4.110 0.000 -1.0 6
7 1 0.000 0.000 4.110 -1.0 8
8 2 2.055 2.055 6.165 1.0 9
9 1 4.110 0.000 4.110 -1.0 10
10 2 6.165 2.055 6.165 1.0 11
11 1 0.000 4.110 4.110 -1.0 12
12 2 2.055 6.165 6.165 1.0 13
13 1 4.110 4.110 4.110 -1.0 14
14 2 6.165 6.165 6.165 1.0 15
15 3 5.565 6.165 1.455 -0.5 7
16 3 6.765 6.165 2.655 -0.5 16
[15]:
am.plot.py3Dmol.view_3d(d_system, height=400, width=400)

You appear to be running in JupyterLab (or JavaScript failed to load for some other reason). You need to install the 3dmol extension:
jupyter labextension install jupyterlab_3dmol