Multi-species Dislocation Systems

The previous section discussed constructing cylindrical dislocation cells, using single-species systems as case studies. The dislocation classes in matscipy.dislocation can also be applied to systems which have much more chemical complexity. However, the following restrictions apply:

  1. The desired system can be expressed in a cubic lattice

  2. The desired system shares on-lattice geometry with an existing “base” crystal structure

As an example, let’s take Zincblende GaAs and compare with a diamond lattice:

from ase.build import bulk
from ase.lattice.cubic import Diamond
import numpy as np
import nglview # this import is necessary for rendering of the 3D view
from visualisation import interactive_view
from ase.visualize import view

# Data from https://doi.org/10.1080/08927022.2011.602975
alat = 11.306/2
C11 = 98.47
C12 = 15.25
C44 = 57.89

GaAs = bulk("GaAs", crystalstructure="zincblende", cubic=True, a=alat)

diamond = Diamond("C", latticeconstant=alat)

gaas_pos = GaAs.get_scaled_positions()
dia_pos = diamond.get_scaled_positions()

# Sort the coords, as bulk uses a different atom order
gaas_idxs = np.lexsort((gaas_pos[:, 0], gaas_pos[:, 1], gaas_pos[:, 2]))
dia_idxs = np.lexsort((dia_pos[:, 0], dia_pos[:, 1], dia_pos[:, 2]))
print("GaAs Fractional Coordinates")
print(gaas_pos[gaas_idxs, :])
print()
print("Diamond Fractional Coordinates")
print(dia_pos[dia_idxs, :])

interactive_view(GaAs, name="GaAs Bulk")
/usr/lib/python3/dist-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.17.3 and <1.25.0 is required for this version of SciPy (detected version 1.26.4
  warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion}"
GaAs Fractional Coordinates
[[0.   0.   0.  ]
 [0.5  0.5  0.  ]
 [0.25 0.25 0.25]
 [0.75 0.75 0.25]
 [0.5  0.   0.5 ]
 [0.   0.5  0.5 ]
 [0.75 0.25 0.75]
 [0.25 0.75 0.75]]

Diamond Fractional Coordinates
[[0.   0.   0.  ]
 [0.5  0.5  0.  ]
 [0.25 0.25 0.25]
 [0.75 0.75 0.25]
 [0.5  0.   0.5 ]
 [0.   0.5  0.5 ]
 [0.75 0.25 0.75]
 [0.25 0.75 0.75]]

We can see that the fractional coordinates of the Zincblende GaAs are the same as the Diamond structure we generated. We can therefore say that Zincblende shares geometry with Diamond. The displacement field used to generate dislocation structures is agnostic to atomic chemistry, and so we can model Zincblende dislocations as if they were dislocations in a Diamond crystal with the lattice constant and elastic properties of the Zincblende crystal.

To build a dislocation with this GaAs bulk, we can simply pass it as an argument in place of the lattice constant:

from matscipy.dislocation import DiamondGlide90degreePartial

disloc = DiamondGlide90degreePartial(GaAs, C11, C12, C44)

GaAs_bulk, GaAs_dislocation = disloc.build_cylinder(radius=3 * alat)

disloc.view_cyl(GaAs_dislocation, scale=0.35, CNA_color=False, add_bonds=True)

Additional Dislocations in Multispecies Systems

Dislocations in multispecies systems have additiional complexity over those in single-species crystals, due to the breaking of some symmetries caused by the added chemical complexity. For our Zincblende GaAs example, this means that we can have two different forms of some of our dislocations: \(\alpha\) (As-terminated), and \(\beta\) (Ga-terminated).

\(\alpha\)-\(90^\circ\) Partial Dislocation in GaAs:

# alpha-90 degree dislocation
GaAs = bulk("GaAs", crystalstructure="zincblende", cubic=True, a=alat)
symbols = np.array(GaAs.get_chemical_symbols())
# Swap Ga <-> As to get other alpha dislocation
new_symbols = symbols.copy()
new_symbols[symbols == "Ga"] = "As"
new_symbols[symbols == "As"] = "Ga"
GaAs.set_chemical_symbols(new_symbols)
disloc = DiamondGlide90degreePartial(GaAs, C11, C12, C44)

GaAs_bulk, GaAs_dislocation = disloc.build_cylinder(radius=3 * alat)
view = disloc.view_cyl(GaAs_dislocation, scale=0.35, CNA_color=False, add_bonds=True,
                        disloc_names=["GaAs 1/6<112> Alpha-90 degree partial"])

view.control.zoom(0.8)
view

\(\beta\)-\(90^\circ\) Partial Dislocation in GaAs:

GaAs = bulk("GaAs", crystalstructure="zincblende", cubic=True, a=alat)
# beta dislocation is the one done by default, for the bulk built by ase.build.bulk
disloc = DiamondGlide90degreePartial(GaAs, C11, C12, C44)

GaAs_bulk, GaAs_dislocation = disloc.build_cylinder(radius=3 * alat)
view = disloc.view_cyl(GaAs_dislocation, scale=0.35, CNA_color=False, add_bonds=True,
                        disloc_names=["GaAs 1/6<112> Beta-90 degree partial"])

view.control.zoom(0.8)
view

Dislocations in Disordered Systems

Generating dislocation structures for systems which have some chemical disorder is also possible, with some caveats:

  1. The generation routines will only work reliably when given on-lattice bulk structures with cubic cells

  2. The generated structure is based on a periodic replication of the base unit_cell, thus won’t have true disorder

  3. The displacement field applied to the bulk structure does not depend on atomic species - lattice distortions caused by the disorder will not be captured

With these in mind, a recommended workflow would be to start by generating the dislocation system for an ordered system, but using the elastic constants of the disordered system. From there, the disorder can be applied by simply changing the chemical symbols of the atoms to match the target composition.

To show a worked example of this, consider the alloy \(\text{In}_{0.5} \text{Ga}_{0.5} \text{As}\). This should form in a Zincblende structure, where the Ga sites from the previous GaAs bulk are now 50% occupied by In.

In order to model this, we can generate a dislocation for GaAs, using the lattice constant and elastic properties of \(\text{In}_{0.5} \text{Ga}_{0.5} \text{As}\). This can be done by passing the 6x6 Voigt elasticity matrix to the C= argument, rather than passing just C11, C12, and C44 as was done previously.

NOTE: Whilst disordered systems like this \(\text{In}_{0.5} \text{Ga}_{0.5} \text{As}\) example should have off-lattice distortions in the bulk state, it is heavily recommended that the dislocation structures are generated using an on-lattice crystal. This is because the off-lattice structure will interact differently with the continuum displacement field, which could lead to overlapping/extremely close atoms, or generally incorrect core structures. The off-lattice distortions should ideally be found by relaxing the dislocation structure built by the dislocaion classes.

from ase.build import bulk
from matscipy.dislocation import DiamondGlide90degreePartial

# Data from https://doi.org/10.1080/08927022.2011.602975
alat = 11.2402/2

# Reproduce data from Table 2 for In0.5 Ga0.5 As
C11, C22, C33, C12, C13, C23, C44, C55, C66 = \
    120.31, 120.35, 121.12, 55.87, 57.24, 57.29, 58.26, 58.33, 58.25

# Construct 6x6 elasticity tensor
C = np.array([
    [C11, C12, C13, 0,   0,   0],
    [C12, C22, C23, 0,   0,   0],
    [C13, C23, C33, 0,   0,   0],
    [0,   0,   0,   C44, 0,   0],
    [0,   0,   0,   0,   C55, 0],
    [0,   0,   0,   0,   0,   C66]
])

GaAs = bulk("GaAs", crystalstructure="zincblende", cubic=True, a=alat)


disloc = DiamondGlide90degreePartial(GaAs, C=C)

GaAs_bulk, GaAs_dislocation = disloc.build_cylinder(radius=3 * alat)

disloc.view_cyl(GaAs_dislocation, scale=0.35, CNA_color=False, add_bonds=True,
                        disloc_names=["GaAs 1/6<112> Beta-90 degree partial"])

From this GaAs structure, we then do Monte Carlo sampling to introduce 50% Indium to the structure:

import numpy as np

np.random.seed(1)

species = np.array(GaAs_dislocation.get_chemical_symbols())

Ga_idxs = np.argwhere(species == "Ga")[:, 0]

# Choose random half of the idxs to be In
In_idxs = sorted(np.random.choice(Ga_idxs, size=int(Ga_idxs.shape[0]/2), replace=False))

# Introduce the chemical disorder in In-Ga sites
species[In_idxs] = "In"

InGaAs_bulk = GaAs_bulk.copy()
InGaAs_bulk.set_chemical_symbols(species)

InGaAs_dislocation = GaAs_dislocation.copy()
InGaAs_dislocation.set_chemical_symbols(species)

view = disloc.view_cyl(GaAs_dislocation, scale=0.35, CNA_color=False, add_bonds=True,
                        disloc_names=["InGaAs 1/6<112> Alpha-90 degree partial"])

# In and Ga have almost the same default colors in nglview
# so we add another component with the In atoms in red to
# see the chemical disorder better
In_ats = InGaAs_dislocation[In_idxs]
c = view.add_component(nglview.ASEStructure(In_ats),
                       default_representation=False)
c.add_spacefill(radius=1.0, color="red")
view