Defect generation

Defect generation#

defermi can be used to generate defects structures to be used in atomistic simulations or analysis. The library returns objects from the defects module, in particular:

  • Vacancy

  • Substitutions

  • Interstitials

defermi uses the pymatgen.symmetry.analyzer.SpacegroupAnalyzer class to defect non-symmetry-equivalent lattice sites, and returns for each a defect object.

We start from a pristine structure, in this example from the tetragonal phase of \(\mathrm{BaTiO_3}\).

[17]:
from pymatgen.core import Structure

structure_bulk = Structure.from_dict({
  "@module": "pymatgen.core.structure", "@class": "Structure", "charge": 0,
  "lattice": {"matrix": [
                        [3.99037921, 0.0, 2.4434025634553223e-16],
                        [6.417019188399763e-16, 3.99037921, 2.4434025634553223e-16],
                        [0.0, 0.0, 4.10265539]],
                        "pbc": [True, True, True],
                        "a": 3.99037921, "b": 3.99037921, "c": 4.10265539,
                        "alpha": 90.0, "beta": 90.0, "gamma": 89.99999999999999,
                        "volume": 65.32709969254628},
  "properties": {},
  "sites": [
    {"species": [{"element": "Ba","occu": 1}], "abc": [0.5, 0.5, 0.5825414600000001], "properties": {}, "label": "Ba2+", "xyz": [1.9951896050000002, 1.995189605, 2.38996686076747]},
    {"species": [{"element": "Ti","occu": 1}], "abc": [0.0, 0.0, 0.1000427], "properties": {}, "label": "Ti4+", "xyz": [0.0, 0.0, 0.41044072238515295]},
    {"species": [{"element": "O", "occu": 1}], "abc": [0.0, 0.5, 0.06422054], "properties": {}, "label": "O2-", "xyz": [3.2085095941998815e-16, 1.995189605, 0.26347474457971076]},
    {"species": [{"element": "O", "occu": 1}], "abc": [0.5, 0.0, 0.06422054], "properties": {}, "label": "O2-", "xyz": [1.995189605, 0.0, 0.26347474457971076]},
    {"species": [{"element": "O", "occu": 1}], "abc": [0.0, 0.0, 0.54897175], "properties": {}, "label": "O2-", "xyz": [0.0, 0.0, 2.252241909095232]}
  ]
})
structure_bulk
[17]:
Structure Summary
Lattice
    abc : 3.99037921 3.99037921 4.10265539
 angles : 90.0 90.0 90.0
 volume : 65.32709969254628
      A : np.float64(3.99037921) np.float64(0.0) np.float64(2.4434025634553223e-16)
      B : np.float64(6.417019188399763e-16) np.float64(3.99037921) np.float64(2.4434025634553223e-16)
      C : np.float64(0.0) np.float64(0.0) np.float64(4.10265539)
    pbc : True True True
PeriodicSite: Ba2+ (Ba) (1.995, 1.995, 2.39) [0.5, 0.5, 0.5825]
PeriodicSite: Ti4+ (Ti) (0.0, 0.0, 0.4104) [0.0, 0.0, 0.1]
PeriodicSite: O2- (O) (3.209e-16, 1.995, 0.2635) [0.0, 0.5, 0.06422]
PeriodicSite: O2- (O) (1.995, 0.0, 0.2635) [0.5, 0.0, 0.06422]
PeriodicSite: O2- (O) (0.0, 0.0, 2.252) [0.0, 0.0, 0.549]

Vacancies#

Specify which elements must form a vacancy with the elements argument. If elements is not specified vacancies for all species are generated. Generate a defect in a supercell with the supercell_size argument. Pass kwargs to the SpaceGroupAnalyzer class to change symmetry criteria for the lattice site classification.

[ ]:
from defermi.generator import create_vacancies, create_interstitials


defects = create_vacancies(structure=structure_bulk, elements=None, supercell_size=3)
defects
[Defect: type=Vacancy, species=Ba, label=a, site= [0.16666667 0.16666667 0.19418049],
 Defect: type=Vacancy, species=Ti, label=a, site= [0.         0.         0.03334757],
 Defect: type=Vacancy, species=O, label=a, site= [0.         0.16666667 0.02140685],
 Defect: type=Vacancy, species=O, label=b, site= [0.         0.         0.18299058]]
The function has generated a list of four objects, because we have only one possible site for Ba and Ti, but two non-equivalent sites for O. Each non-equivalent Defect gets assigned a different label.
By default defect objects are created without a charge property. Use the set_charge method to assign it. Several properties can be accessed through the Defect object. Use the generate_defect_structure method to create a Structure object containing the defect.
[21]:
defect = defects[-1]
defect.set_charge(2) # set defect charge

print(f"Defect name: {defect.name}")
print(f"Defect type: {defect.type}")
print(f"Defect species: {defect.specie}")
print(f"Defect label: {defect.label}")
print(f"Particle number difference btw defect and pristine material: {defect.delta_atoms}")
print(f"Symbol: {defect.symbol_with_charge}")
print(f"Symbol in Kröger-Vink notation: {defect.symbol_with_charge_kv}")

# get structure containing defect
defect.generate_defect_structure().composition
Defect name: Vac_O(b)
Defect type: Vacancy
Defect species: O
Defect label: b
Particle number difference btw defect and pristine material: {'O': -1}
Symbol: $V_{O}$(b)$^{+2}$
Symbol in Kröger-Vink notation: $V_{O}$(b)$^{°°}$
[21]:
Composition('Ba27 Ti27 O80')

Substitutions#

The same workflow applies for Substitution objects. Use the elements_to_replace argument to specify the substituting and substituted elements.
Pass a dict in this format: {"element to be replaced":"element to replace with"}.

Let’s substitute Ti with Fe and assign it a \(-1\) charge.

[28]:
from defermi.generator import create_substitutions

defects = create_substitutions(
                        structure=structure_bulk,
                        elements_to_replace={'Ti':'Fe'},
                        supercell_size=3)

defect = defects[0]
defect.set_charge(-1)
print(defect.symbol_with_charge)

defect.generate_defect_structure().composition
$Fe_{Ti}$(a)$^{-1}$
[28]:
Composition('Ba27 Fe1 Ti26 O81')

Interstitials#

Interstitials are definitely not as straightforward as vacancies and substitutions. defermi relies on pymatgen.analysis.defects.generators.VoronoiInterstitialGenerator. Change defaults using kwargs:

  • clustering_tol: Tolerance for clustering the Voronoi nodes

  • min_dist: Minimum distance between an interstitial and the nearest atom

  • ltol: Tolerance for lattice matching

  • stol: Tolerance for structure matching

  • angle_tol: Angle tolerance for structure matching

  • kwargs: Additional keyword arguments for the TopographyAnalyzer constructor

The function returns a list of Interstitial objects.

[31]:
from defermi.generator import create_interstitials

defects = create_interstitials(structure=structure_bulk,elements=['O'],supercell_size=3)

defects
[31]:
[Defect: type=Interstitial, species=O, label=mult216, site= [0.07860922 0.74527589 0.60653553],
 Defect: type=Interstitial, species=O, label=mult81, site= [0.33333333 0.83333333 0.52150661]]
[37]:
# lattice site multiplicity is stored in the defect label
for defect in defects:
    print(f"Interstitial with multiplicity: {defect.label.strip('mult')}")
    defect.set_charge(-2) # set interstitial charge

    print(f"Defect name: {defect.name}")
    print(f"Defect type: {defect.type}")
    print(f"Defect species: {defect.specie}")
    print(f"Defect label: {defect.label}")
    print(f"Particle number difference btw defect and pristine material: {defect.delta_atoms}")
    print(f"Symbol: {defect.symbol_with_charge}")
    print(f"Symbol in Kröger-Vink notation: {defect.symbol_with_charge_kv}")


    # get structure containing defect
    print(f"Composition: {defect.generate_defect_structure().composition}\n")
Interstitial with multiplicity: 216
Defect name: Int_O(mult216)
Defect type: Interstitial
Defect species: O
Defect label: mult216
Particle number difference btw defect and pristine material: {'O': 1}
Symbol: $O_i$(mult216)$^{-2}$
Symbol in Kröger-Vink notation: $O_i$(mult216)$^{''}$
Composition: Ba27 Ti27 O82

Interstitial with multiplicity: 81
Defect name: Int_O(mult81)
Defect type: Interstitial
Defect species: O
Defect label: mult81
Particle number difference btw defect and pristine material: {'O': 1}
Symbol: $O_i$(mult81)$^{-2}$
Symbol in Kröger-Vink notation: $O_i$(mult81)$^{''}$
Composition: Ba27 Ti27 O82