Building cylindrical configurations with dislocations

The matscipy.dislocation provides a set of tools to create atomistic configurations containing dislocations. In this example we focus on cylindrical configurations. In order to create a dislocation we start with a cylinder of bulk material oriented along the vector of the future dislocation line \(\vec l\). By convention assumed in matscipy.dislocation Z direction of the cell always corresponds to the dislocation line \(\vec l\). Then a displacement field is applied to the cylinder and outer radial shell is fixed in order to stabilise the configuration. So we end up with periodic boundary conditions along the dislocation line (Z) and fixed boundaries along X and Y directions. As shown on the figure above, screw dislocations are characterised by a displacement with corresponding burgers vector \(\vec b\) parallel to the dislocation line \(\vec l\), while edge dislocations have the burgers vector \(\vec b\) perpendicular to \(\vec l\). matscipy uses an anisotropic solution within Stroh formalism to generate displacement field as implemented in atomman package.

For the interactive visualisation of the structures we will use nglview which allows viewing atomistic structures interactively within an IPython/Jupyter notebooks. We will also color atoms according to the crystallographic structure identified by Common Neighbour Analysis algoritm and its extention for diamond structure implemented in OVITO package. OVITO, atomman and nglview are not part of the default dependencies of matscipy and require separate installation. Keep that in mind while running these examples as well test in test_dislocation.py since the majority of the tests there require this modules and thus will be skipped if the modules are not found in your system. Please note that for this example we use very small systems (small radius). For production calculations one should do a convergence tests with the system size in order to ensure that fixed boundaries do not affect the studied properties.

import numpy as np
import nglview # this import is necessary for rendering of the 3D view

Accessing Key Dislocation Properties

As defined in a dimensionless (alat=1) frame, each kind of dislocation has several key properties which describe the geometric layout of the atomic cell, and also the position and orientation of the dislocation. Such properties are stored in matscipy as attributes of each dislocation class, such that they can be accessed without actually needing to construct a dislocation.

As an example:

from matscipy.dislocation import BCCMixed111Dislocation

print("For a BCC 1/2<111>{110} Mixed Dislocation")
print()

print("The dislocation is oriented in a cell described by the miller indices: ")
print(BCCMixed111Dislocation.axes)

print("Dimensionless burgers vector is: ", BCCMixed111Dislocation.burgers_dimensionless)

print("Dislocation core will be at fractional coords:\n", 
      BCCMixed111Dislocation.unit_cell_core_position_dimensionless, " within a unit cell")
/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}"
For a BCC 1/2<111>{110} Mixed Dislocation

The dislocation is oriented in a cell described by the miller indices: 
[[ 1 -1 -2]
 [ 1  1  0]
 [ 1 -1  1]]
Dimensionless burgers vector is:  [ 0.5 -0.5 -0.5]
Dislocation core will be at fractional coords:
 [0.16666667 0.16666667 0.        ]  within a unit cell

Available Dislocation Systems

The available dislocation systems are:

import matscipy.dislocation as disloc_mod
import inspect
# Find all classes in matscipy.dislocation which inherit from 
# the Abstract Base Class CubicCrystalDislocation
for name, attr in disloc_mod.__dict__.items():
    if inspect.isclass(attr):
        if issubclass(attr, disloc_mod.CubicCrystalDislocation) and \
            attr not in [disloc_mod.CubicCrystalDislocation,
                         disloc_mod.CubicCrystalDissociatedDislocation]:
            print(name)
CubicCrystalDislocationQuadrupole
Quadrupole
BCCScrew111Dislocation
BCCEdge111Dislocation
BCCEdge111barDislocation
BCCMixed111Dislocation
BCCEdge100Dislocation
BCCEdge100110Dislocation
DiamondGlide30degreePartial
DiamondGlide90degreePartial
DiamondGlideScrew
DiamondGlide60Degree
FCCScrewShockleyPartial
FCCEdgeShockleyPartial
FCCScrew110Dislocation
FCCEdge110Dislocation

Body Centered Cubic

For the case of BCC structure we take tungsten as an example. In order to create a dislocation configuration one has to provide lattice parameter and elastic constants. It is possible to provide these values from literature. However, if you plan to relax the configuration with an interatomic potential, matscipy.dislocation provides a convenient method get_elastic_constants to calculate desired properties. We will use and Embedded Atom Potential from Marinica et. al. 2013 paper (version EAM4) for the case of tungsten.

from matscipy.dislocation import get_elastic_constants
# the calculator to provide forces and energies from the potential
from matscipy.calculators.eam import EAM
eam_calc = EAM("../../tests/w_eam4.fs")

# the function accepts any ASE type of calculator
alat, C11, C12, C44 = get_elastic_constants(calculator=eam_calc, symbol="W", verbose=False)
Hide code cell output
/usr/local/lib/python3.10/dist-packages/matscipy/dislocation.py:485: FutureWarning: Import StrainFilter from ase.filters
  sf = StrainFilter(unit_cell)
print(f"{alat:.3f} (Angstrom), {C11:.2f}, {C12:.2f}, {C44:.2f} (GPa)")
3.143 (Angstrom), 538.90, 219.93, 178.80 (GPa)

The values are in good agreement with corresponding numbers in the paper: 3.143, 523, 202, 161

1/2<111>{110} screw dislocation

The notation 1/2<111>{110} means a dislocation with a burgers vector 1/2<111> and glide plane {110}. For screw dislocation, the dislocation line is parallel to the burgers vector, thus Z direction of the cell will be along <111>. The glide plane {110} fixes the Y direction to be <110> and the X direction is fixed by the geometry to be along <112>. However you do not have to think about it to start since BCCScrew111Dislocation object contains all the necessary information. All you need to do is to pass \(a_0\) and elastic constants \(C_{11}\), \(C_{12}\) and \(C_{44}\) and the symbol of the desired BCC element to the constructor.

from matscipy.dislocation import BCCScrew111Dislocation

W_screw = BCCScrew111Dislocation(alat, C11, C12, C44, symbol="W")

print("Cell orientation:")
print(W_screw.axes)

print("Burgers vector:")
print(W_screw.burgers)
Cell orientation:
[[ 1  1 -2]
 [-1  1  0]
 [ 1  1  1]]
Burgers vector:
[1.57169501 1.57169501 1.57169501]

We are going to use BCCScrew111Dislocation.build_cylinder() method to build the cells. All the necessary parameters are passed automatically and we only need to chose the radius of the cell in (X,Y) plane. The function returns reference bulk cell and a cell containing dislocation. The displacement field is applied iteratively until a converged value is achieved, the printed output shows the difference between the steps. The radius provided is a parameter is a radius of unconstrained region around the core. The outer shell of fixed atoms is added on top of this. The default value is 10 Angstrom which is about two times larger than the cutoff for the used interatomic potential. The information about which atoms are fixed is stored in fix_mask array and can be accessed via W_screw_dislo.get_array('fix_mask').

W_screw_bulk, W_screw_dislo = W_screw.build_cylinder(radius=20)

print("\nCell vectors:")
print(W_screw_dislo.cell.array)

print(f"\nBurgers vector lenth: {np.linalg.norm(W_screw.burgers):.2f} Angstrom")
disloc SCF 0 |d1-d2|_inf = 0.0007002983806931873
disloc SCF 1 |d1-d2|_inf = 0.0003518249861804712
disloc SCF 2 |d1-d2|_inf = 0.0001767544009220745
disloc SCF 3 |d1-d2|_inf = 8.880016897117038e-05
disloc SCF 4 |d1-d2|_inf = 4.4612580869241025e-05
disloc SCF 5 |d1-d2|_inf = 2.241304711536607e-05
disloc SCF 6 |d1-d2|_inf = 1.1260157359777034e-05
disloc SCF 7 |d1-d2|_inf = 5.657023923633098e-06
disloc SCF 8 |d1-d2|_inf = 2.8420490619796013e-06
disloc SCF 9 |d1-d2|_inf = 1.427825474326072e-06
disloc SCF 10 |d1-d2|_inf = 7.173294831464005e-07

Cell vectors:
[[46.19820981  0.          0.        ]
 [ 0.         44.45424812  0.        ]
 [ 0.          0.          2.72225562]]

Burgers vector lenth: 2.72 Angstrom

Note

In BCC we solve for the displacements self-consistently (note the disloc SCF in the above output). This approach can cause unexpected behaviour in rare occurences where atoms get close to divergences in the Continuum Linear Elastic (CLE) solution. The self-consistency can be disabled by passing self_consistent=False to build_cylinder, or the approach can be bounded to a smaller region close to the dislocation core using e.g. r_sc=30 to only apply SC to the first 30 Angstrom of atoms around the core.

Now we can use CubicCrystalDislocation.view_cyl to look at the created structure with an NGL interactive view. Hovering your mouse over an atom will show chemical symbol of the atom and the structure identified by CNA algorithm. Dislocation is shown with an arrow corresponding to the dislocation line vector \(\vec l\). Hovering over the dislocation will display the dislocation name. Moreover, you can use your mouse to control the view:

  • Translation: right click + drag

  • Rotation: left click + drag

  • Z-axis rotation: Ctrl + right click + drag

  • Zoom: scroll wheel

  • Center view: left click on the desired atom

W_screw.view_cyl(W_screw_dislo)

It can be seen that most of the cell is identified as BCC structure with some grey atoms identified as Other. These atoms represent the defect atoms, where the algorithm could not assign a crystallographic structure. In this case we have defect atoms at the dislocation core and on the artificial free surfaces on the edges of the cell. The atoms at the surface are part of fixed region of the cell.

Here we have a cell with the length of one Burgers vector \(|\vec b| = \frac{\sqrt{3}}{2}a_0\) along the dislocation line. With the periodic boundary conditions along Z, it corresponds to infinitely long straight dislocation line. Note that the periodic boundary conditions along the dislocation line are not applied in the visualisation. It makes it easier to see the displacement, but you might notice the atoms outside the simulation box.

To increase the size of the cell along the line we can rely on the magic of ASE and simply multiply the cell.

longer_W_screw_dislo = W_screw_dislo * [1, 1, 10]
W_screw.view_cyl(longer_W_screw_dislo)

If you want to save the configuration in a file for further analysis or as an input for a code you can use build in ASE write method as longer_W_screw_dislo.write(filename). The method supports a wide range of formats including xyz and LAMMPS data files. Do not forget to take into account fixed atoms if you use the saved file as an input for a simulation code like LAMMPS.

1/2<111>{110} edge dislocation

As we said before, for edge dislocations burgers vectpr \(\vec b\) is perpendicular to the dislocation \(\vec l\). So here, we have the same glide plane of (110) which fixes the cell Y direction to <110>. X direction now will be along burgers vector <111> and Z dislocation line direction <112>.

from matscipy.dislocation import BCCEdge111Dislocation

W_edge = BCCEdge111Dislocation(alat, C11, C12, C44, symbol="W")

print("Cell orientation:")
print(W_edge.axes)

print("Burgers vector:")
print(W_edge.burgers)
Cell orientation:
[[ 1  1  1]
 [ 1 -1  0]
 [ 1  1 -2]]
Burgers vector:
[1.57169501 1.57169501 1.57169501]
W_edge_bulk, W_edge_dislo = W_edge.build_cylinder(radius=15)

print("\nCell vectors:")
print(W_edge_dislo.cell.array)

print(f"\nBurgers vector lenth: {np.linalg.norm(W_edge.burgers):.2f} Angstrom")
disloc SCF 0 |d1-d2|_inf = 0.08751883578064723
disloc SCF 1 |d1-d2|_inf = 0.040861196124218124
disloc SCF 2 |d1-d2|_inf = 0.022825263559017595
disloc SCF 3 |d1-d2|_inf = 0.013827362573782642
disloc SCF 4 |d1-d2|_inf = 0.008309453605807038
disloc SCF 5 |d1-d2|_inf = 0.004949366223313656
disloc SCF 6 |d1-d2|_inf = 0.002920835307407499
disloc SCF 7 |d1-d2|_inf = 0.001707589422488942
disloc SCF 8 |d1-d2|_inf = 0.0009889006148837698
disloc SCF 9 |d1-d2|_inf = 0.0005672574174525047
disloc SCF 10 |d1-d2|_inf = 0.0003222508524113876
disloc SCF 11 |d1-d2|_inf = 0.00018124374430700252
disloc SCF 12 |d1-d2|_inf = 0.00010087332160230167
disloc SCF 13 |d1-d2|_inf = 5.551627821231975e-05
disloc SCF 14 |d1-d2|_inf = 3.0181880222079904e-05
disloc SCF 15 |d1-d2|_inf = 1.6185334900387094e-05
disloc SCF 16 |d1-d2|_inf = 8.543846241548803e-06
disloc SCF 17 |d1-d2|_inf = 4.426490514020109e-06
disloc SCF 18 |d1-d2|_inf = 2.2410081775836588e-06
disloc SCF 19 |d1-d2|_inf = 1.1012012560707163e-06
disloc SCF 20 |d1-d2|_inf = 5.193489800436879e-07

Cell vectors:
[[32.66706744  0.          0.        ]
 [ 0.         31.11797368  0.        ]
 [ 0.          0.          7.69970164]]

Burgers vector lenth: 2.72 Angstrom

It can be seen from the print output of W_edge.build_cylinder() that the case of edge dislocation the requires more iterations to achieve converged displacement field.

W_edge.view_cyl(W_edge_dislo, scale=0.25)

1/2<111>{110} mixed dislocation

For mixed dislocation the cell vector are the same as for the screw dislocation. The difference is that the displacement vector is applied along <111> direction that is not parallel to the Z direction: [\(1\bar 11\)] and [\(1\bar 1 \bar1\)] with an angle of 70.5 degrees between the vectors. This leads to both edge and screw component in the displacement and thus the name mixed dislocation.

from matscipy.dislocation import BCCMixed111Dislocation

W_mixed = BCCMixed111Dislocation(alat, C11, C12, C44, symbol="W")

print("Cell orientation:")
print(W_mixed.axes)

print("Burgers vector:")
print(W_mixed.burgers)
Cell orientation:
[[ 1 -1 -2]
 [ 1  1  0]
 [ 1 -1  1]]
Burgers vector:
[ 1.57169501 -1.57169501 -1.57169501]
W_mixed_bulk, W_mixed_dislo = W_mixed.build_cylinder(radius=20)

print("\nCell vectors:")
print(W_mixed_dislo.cell.array)

print(f"\nBurgers vector length: {np.linalg.norm(W_mixed.burgers):.2f} Angstrom")

W_mixed.view_cyl(W_mixed_dislo, scale=0.5)
disloc SCF 0 |d1-d2|_inf = 0.1456039707936717
disloc SCF 1 |d1-d2|_inf = 0.059907573464541675
disloc SCF 2 |d1-d2|_inf = 0.028503341908167584
disloc SCF 3 |d1-d2|_inf = 0.014419391826502067
disloc SCF 4 |d1-d2|_inf = 0.007081941950075232
disloc SCF 5 |d1-d2|_inf = 0.003368346473116495
disloc SCF 6 |d1-d2|_inf = 0.0015423024365132931
disloc SCF 7 |d1-d2|_inf = 0.0007171164954145048
disloc SCF 8 |d1-d2|_inf = 0.0005234232461244215
disloc SCF 9 |d1-d2|_inf = 0.0003433121906495362
disloc SCF 10 |d1-d2|_inf = 0.00021084706513319063
disloc SCF 11 |d1-d2|_inf = 0.00012359047161103476
disloc SCF 12 |d1-d2|_inf = 6.984771376150611e-05
disloc SCF 13 |d1-d2|_inf = 3.827834935354879e-05
disloc SCF 14 |d1-d2|_inf = 2.0405799376010947e-05
disloc SCF 15 |d1-d2|_inf = 1.0596408768437371e-05
disloc SCF 16 |d1-d2|_inf = 5.359853927577873e-06
disloc SCF 17 |d1-d2|_inf = 2.6369154058070166e-06
disloc SCF 18 |d1-d2|_inf = 1.257692343825667e-06
disloc SCF 19 |d1-d2|_inf = 5.78128418915469e-07

Cell vectors:
[[46.19820981  0.          0.        ]
 [ 0.         44.45424812  0.        ]
 [ 0.          0.          2.72225562]]

Burgers vector length: 2.72 Angstrom

<100>{110} edge ‘junction’ dislocation

So called junction dislocations with burdgers vector along <100> can be formed in the reactions between more abundant dislocations with burgers vector 1/2<111> such as:

\[ \frac{1}{2}[1\bar{1}1] + \frac{1}{2}[11\bar{1}] = [100] \]

They share the same glide plane ad 1/2<111> dislocations and can play important role in impurity segregation.

from matscipy.dislocation import BCCEdge100110Dislocation

W_100110_edge = BCCEdge100110Dislocation(alat, C11, C12, C44, symbol="W")

print("Cell orientation:")
print(W_100110_edge.axes)

print("Burgers vector:")
print(W_100110_edge.burgers)
Cell orientation:
[[ 1  0  0]
 [ 0  1  1]
 [ 0 -1  1]]
Burgers vector:
[3.14339003 0.         0.        ]
W_100110_edge_bulk, W_100110_edge_dislo = W_100110_edge.build_cylinder(radius=17)
W_100110_edge.view_cyl(W_100110_edge_dislo, scale=0.3, line_color=[1, 0, 1])
disloc SCF 0 |d1-d2|_inf = 0.1280057024455897
disloc SCF 1 |d1-d2|_inf = 0.06116283180138693
disloc SCF 2 |d1-d2|_inf = 0.033228942952467116
disloc SCF 3 |d1-d2|_inf = 0.01883401090377368
disloc SCF 4 |d1-d2|_inf = 0.010317674555602646
disloc SCF 5 |d1-d2|_inf = 0.005479968807368396
disloc SCF 6 |d1-d2|_inf = 0.0028203538962097985
disloc SCF 7 |d1-d2|_inf = 0.0014016587037598283
disloc SCF 8 |d1-d2|_inf = 0.000667833269524451
disloc SCF 9 |d1-d2|_inf = 0.00030095624285227107
disloc SCF 10 |d1-d2|_inf = 0.00012483600670459838
disloc SCF 11 |d1-d2|_inf = 7.214731613225389e-05
disloc SCF 12 |d1-d2|_inf = 5.1322790716401556e-05
disloc SCF 13 |d1-d2|_inf = 3.3733459126494836e-05
disloc SCF 14 |d1-d2|_inf = 2.100906770108324e-05
disloc SCF 15 |d1-d2|_inf = 1.2556644481520607e-05
disloc SCF 16 |d1-d2|_inf = 7.252149701431065e-06
disloc SCF 17 |d1-d2|_inf = 4.062447767738675e-06
disloc SCF 18 |d1-d2|_inf = 2.2105784651671456e-06
disloc SCF 19 |d1-d2|_inf = 1.168236141602108e-06
disloc SCF 20 |d1-d2|_inf = 6.090321286178479e-07

<100>{001} edge dislocation

This is the same junction dislocation but lying in a different glide plane: (001).

from matscipy.dislocation import BCCEdge100Dislocation

W_100_edge = BCCEdge100Dislocation(alat, C11, C12, C44, symbol="W")

print("Cell orientation:")
print(W_100_edge.axes)

print("Burgers vector:")
print(W_100_edge.burgers)
Cell orientation:
[[ 1  0  0]
 [ 0  0 -1]
 [ 0  1  0]]
Burgers vector:
[3.14339003 0.         0.        ]
W_100_edge_bulk, W_100_edge_dislo = W_100_edge.build_cylinder(radius=20)
W_100_edge.view_cyl(W_100_edge_dislo, scale=0.4, line_color=[1, 0, 1])
disloc SCF 0 |d1-d2|_inf = 0.14861912042082115
disloc SCF 1 |d1-d2|_inf = 0.06368262746234166
disloc SCF 2 |d1-d2|_inf = 0.031187863915751214
disloc SCF 3 |d1-d2|_inf = 0.0157549793956056
disloc SCF 4 |d1-d2|_inf = 0.007773687670121807
disloc SCF 5 |d1-d2|_inf = 0.0037396753216583922
disloc SCF 6 |d1-d2|_inf = 0.00174733333716387
disloc SCF 7 |d1-d2|_inf = 0.0007877019555050102
disloc SCF 8 |d1-d2|_inf = 0.00036781757086612465
disloc SCF 9 |d1-d2|_inf = 0.0002595603858464024
disloc SCF 10 |d1-d2|_inf = 0.00016731771283629016
disloc SCF 11 |d1-d2|_inf = 0.00010183918931772062
disloc SCF 12 |d1-d2|_inf = 5.948393096466553e-05
disloc SCF 13 |d1-d2|_inf = 3.364317526699523e-05
disloc SCF 14 |d1-d2|_inf = 1.852288603898522e-05
disloc SCF 15 |d1-d2|_inf = 9.958811746590968e-06
disloc SCF 16 |d1-d2|_inf = 5.237887889419923e-06
disloc SCF 17 |d1-d2|_inf = 2.6968616098077547e-06
disloc SCF 18 |d1-d2|_inf = 1.3589880443198865e-06
disloc SCF 19 |d1-d2|_inf = 6.694323613221087e-07

Face Centered Cubic

As an example of FCC material we will consider Ni and an interatomic potential from Bonny et. al.

eam_calc = EAM("../../tests/FeCuNi.eam.alloy")

# the function accepts any ASE type of calculator
alat, C11, C12, C44 = get_elastic_constants(calculator=eam_calc, symbol="Ni", verbose=False)
print(f"{alat:.3f} (Angstrom), {C11:.2f}, {C12:.2f}, {C44:.2f} (GPa)")
3.520 (Angstrom), 244.07, 148.85, 125.62 (GPa)

1/2<110>{111} screw dislocation (perfect and dissociated)

from matscipy.dislocation import FCCScrew110Dislocation

Ni_screw = FCCScrew110Dislocation(alat, C11, C12, C44, symbol="Ni")

print("Cell orientation:")
print(Ni_screw.axes)

print("Burgers vector:")
print(Ni_screw.burgers)
Cell orientation:
[[ 1  1 -2]
 [ 1  1  1]
 [ 1 -1  0]]
Burgers vector:
[ 1.76 -1.76  0.  ]
Ni_screw_bulk, Ni_screw_dislo = Ni_screw.build_cylinder(radius=20)


print("\nCell vectors:")
print(Ni_screw_dislo.cell.array)

print(f"\nBurgers vector length: {np.linalg.norm(Ni_screw.burgers):.2f} Angstrom")

Ni_screw.view_cyl(Ni_screw_dislo, line_color=[0, 0, 1])
disloc SCF 0 |d1-d2|_inf = 0.0

Cell vectors:
[[43.11101947  0.          0.        ]
 [ 0.         42.6777319   0.        ]
 [ 0.          0.          2.48901587]]

Burgers vector length: 2.49 Angstrom

Due to stable Intrinsic Stacking Fault (ISF) the 1/2<110> dislocations are not stable and dissociate in two 1/6<112> Shockley partials separated by stacking fault. For example:

\[ \frac{1}{2}[1\bar10] \rightarrow \frac{1}{6}[2\bar1\bar1] + \mathrm{ISF} + \frac{1}{6}[1\bar21] \]

where ISF is intrinsic stacking fault. It is possible to pass a parameter partial_distance to build_cylinder() function in order to create dissociated dislocation. partial distance defines separation distance (length of the stacking fault) of two partial dislocations. The value corresponds to number of glide distances the distance in Angstrom be obtaines as patial_distance * dislocation.glide_distance.

Ni_screw_bulk, Ni_screw_dislo = Ni_screw.build_cylinder(radius=20, partial_distance=5)
print(f"\nExpected partial distance: {5 * Ni_screw.glide_distance:.1f} Angstrom")
Ni_screw.view_cyl(Ni_screw_dislo)
disloc SCF 0 |d1-d2|_inf = 0.022220814733477506
disloc SCF 1 |d1-d2|_inf = 0.0107739038928778
disloc SCF 2 |d1-d2|_inf = 0.005185027906170064
disloc SCF 3 |d1-d2|_inf = 0.002475082781572463
disloc SCF 4 |d1-d2|_inf = 0.0011712409716692351
disloc SCF 5 |d1-d2|_inf = 0.0005491236463885107
disloc SCF 6 |d1-d2|_inf = 0.00025489205141415727
disloc SCF 7 |d1-d2|_inf = 0.00011703200541851588
disloc SCF 8 |d1-d2|_inf = 5.308539745557672e-05
disloc SCF 9 |d1-d2|_inf = 2.5718688654086108e-05
disloc SCF 10 |d1-d2|_inf = 1.2808643934048014e-05
disloc SCF 11 |d1-d2|_inf = 6.368516532406776e-06
disloc SCF 12 |d1-d2|_inf = 3.1610626539113618e-06
disloc SCF 13 |d1-d2|_inf = 1.5662580029607298e-06
disloc SCF 14 |d1-d2|_inf = 7.746418797527355e-07

Expected partial distance: 10.8 Angstrom

Together with FCC (green) and defect atoms (grey) the CNA algorithm identified the atoms of the stacking fault as HCP structure (pink), which is a result of the local change of stacking order of the atomic layers within the defect.

1/2<110>{111} edge dislocation (perfect and dissociated)

from matscipy.dislocation import FCCEdge110Dislocation

Ni_edge = FCCEdge110Dislocation(alat, C11, C12, C44, symbol="Ni")

print("Cell orientation:")
print(Ni_edge.axes)

print("Burgers vector:")
print(Ni_edge.burgers)
Cell orientation:
[[ 1 -1  0]
 [ 1  1  1]
 [-1 -1  2]]
Burgers vector:
[ 1.76 -1.76  0.  ]
Ni_edge_bulk, Ni_edge_dislo = Ni_edge.build_cylinder(radius=20)

print("\nCell vectors:")
print(Ni_edge_dislo.cell.array)

print(f"\nBurgers vector length: {np.linalg.norm(Ni_edge.burgers):.2f} Angstrom")

Ni_edge.view_cyl(Ni_edge_dislo, line_color=[0, 0, 1])
disloc SCF 0 |d1-d2|_inf = 0.15473510917799116
disloc SCF 1 |d1-d2|_inf = 0.06777415250108576
disloc SCF 2 |d1-d2|_inf = 0.03475439294804093
disloc SCF 3 |d1-d2|_inf = 0.018101177738677518
disloc SCF 4 |d1-d2|_inf = 0.008961495147710302
disloc SCF 5 |d1-d2|_inf = 0.004180664619767474
disloc SCF 6 |d1-d2|_inf = 0.0017958199824296694
disloc SCF 7 |d1-d2|_inf = 0.0013438620432931758
disloc SCF 8 |d1-d2|_inf = 0.0009841068440427092
disloc SCF 9 |d1-d2|_inf = 0.0006551466763722313
disloc SCF 10 |d1-d2|_inf = 0.0004090684271416123
disloc SCF 11 |d1-d2|_inf = 0.00024307855806582346
disloc SCF 12 |d1-d2|_inf = 0.00013844319756284307
disloc SCF 13 |d1-d2|_inf = 7.578385209161542e-05
disloc SCF 14 |d1-d2|_inf = 3.9850835624632985e-05
disloc SCF 15 |d1-d2|_inf = 2.0050308024432972e-05
disloc SCF 16 |d1-d2|_inf = 9.565850800474784e-06
disloc SCF 17 |d1-d2|_inf = 4.656306369719976e-06
disloc SCF 18 |d1-d2|_inf = 2.4986817410421747e-06
disloc SCF 19 |d1-d2|_inf = 1.2860867572156431e-06
disloc SCF 20 |d1-d2|_inf = 6.310074034537871e-07

Cell vectors:
[[42.31326979  0.          0.        ]
 [ 0.         42.6777319   0.        ]
 [ 0.          0.          4.31110195]]

Burgers vector length: 2.49 Angstrom
Ni_edge_bulk, Ni_edge_dislo = Ni_edge.build_cylinder(radius=20, partial_distance=10)
print(f"\nExpected partial distance: {10 * Ni_edge.glide_distance:.1f} Angstrom")
Ni_edge.view_cyl(Ni_edge_dislo)
disloc SCF 0 |d1-d2|_inf = 0.06447946338433494
disloc SCF 1 |d1-d2|_inf = 0.0334524697645955
disloc SCF 2 |d1-d2|_inf = 0.017489485207730193
disloc SCF 3 |d1-d2|_inf = 0.009570765143307236
disloc SCF 4 |d1-d2|_inf = 0.005227931148117371
disloc SCF 5 |d1-d2|_inf = 0.002848373595293774
disloc SCF 6 |d1-d2|_inf = 0.0016133883618037678
disloc SCF 7 |d1-d2|_inf = 0.0009239710238140367
disloc SCF 8 |d1-d2|_inf = 0.0005255198257729868
disloc SCF 9 |d1-d2|_inf = 0.000297021349456493
disloc SCF 10 |d1-d2|_inf = 0.000166910817984596
disloc SCF 11 |d1-d2|_inf = 9.32994713158733e-05
disloc SCF 12 |d1-d2|_inf = 5.18968735267189e-05
disloc SCF 13 |d1-d2|_inf = 2.8735088627621086e-05
disloc SCF 14 |d1-d2|_inf = 1.5842041526277495e-05
disloc SCF 15 |d1-d2|_inf = 8.698292994012424e-06
disloc SCF 16 |d1-d2|_inf = 4.757294939351786e-06
disloc SCF 17 |d1-d2|_inf = 2.5921033584078157e-06
disloc SCF 18 |d1-d2|_inf = 1.4072127053482708e-06
disloc SCF 19 |d1-d2|_inf = 7.612349910146587e-07

Expected partial distance: 12.4 Angstrom

Diamond Cubic

As an example of diamond structure we will use Si and potential from work of D. Holland and M. Marder.

from matscipy.calculators.manybody.explicit_forms.stillinger_weber import StillingerWeber,\
                                                                Holland_Marder_PRL_80_746_Si
from matscipy.calculators.manybody import Manybody
calc = Manybody(**StillingerWeber(Holland_Marder_PRL_80_746_Si))

# the function accepts any ASE type of calculator
alat, C11, C12, C44 = get_elastic_constants(calculator=calc, symbol="Si", verbose=False)
print(f"{alat:.3f} (Angstrom), {C11:.2f}, {C12:.2f}, {C44:.2f} (GPa)")
5.431 (Angstrom), 201.46, 51.64, 118.18 (GPa)
from matscipy.dislocation import DiamondGlideScrew

Si_screw = DiamondGlideScrew(alat, C11, C12, C44, symbol="Si")

print("Cell orientation:")
print(Si_screw.axes)

print("Burgers vector:")
print(Si_screw.burgers)
Cell orientation:
[[ 1  1 -2]
 [ 1  1  1]
 [ 1 -1  0]]
Burgers vector:
[ 2.71547494 -2.71547494  0.        ]

1/2<110>{111} screw dislocation (perfect and dissociated)

Si_screw_bulk, Si_screw_dislo = Si_screw.build_cylinder(radius=20)

print("\nCell vectors:")
print(Si_screw_dislo.cell.array)

print(f"\nBurgers vector length: {np.linalg.norm(Si_screw.burgers):.2f} Angstrom")

Si_screw.view_cyl(Si_screw_dislo, scale=0.3, line_color=[0, 0, 1],
                 add_bonds=True, # bonds make it a bit easier to see the structure
                 )
Cell vectors:
[[46.56069608  0.          0.        ]
 [ 0.         47.03340562  0.        ]
 [ 0.          0.          3.84026149]]

Burgers vector length: 3.84 Angstrom

The modification of the CNA algorithm for the diamond structure identifies the defect atoms gradually depending how far they are from the perfect structure. The important outcome for us is now dislocation core and free surface atoms are identified as 1st and 2nd neighbors of the Cubic diamond structure.

As in FCC structure similar dissociation mechanism exists in diamond structure.

Si_screw_bulk, Si_screw_dislo = Si_screw.build_cylinder(radius=20, partial_distance=5)

print(f"Expected partial distance: {5 * Si_screw.glide_distance:.1f} Angstrom")
Si_screw.view_cyl(Si_screw_dislo, scale=0.3, add_bonds=True, line_color=[1, 0, 1]) 
Expected partial distance: 16.6 Angstrom

The stacking fault atoms are identified as Hexagonal diamond structure.

1/2<110>{111} 60 degree screw dislocation (perfect and dissociated)

Due to the particular symmetry of cubic diamond structure, there exist dislocations with 60 degree angle between burgers vector and dislocation line. This dislocation can dissociate in two partials: 30 and 90 degree.

from matscipy.dislocation import DiamondGlide60Degree

Si_60_degree_screw = DiamondGlide60Degree(alat, C11, C12, C44, symbol="Si")

print("Cell orientation:")
print(Si_screw.axes)

print("Burgers vector:")
print(Si_screw.burgers)
Cell orientation:
[[ 1  1 -2]
 [ 1  1  1]
 [ 1 -1  0]]
Burgers vector:
[ 2.71547494 -2.71547494  0.        ]
Si_60_degree_screw_bulk, \
Si_60_degree_screw_dislo = Si_60_degree_screw.build_cylinder(radius=20)

print("\nCell vectors:")
print(Si_60_degree_screw_dislo.cell.array)

print(f"\nBurgers vector length: {np.linalg.norm(Si_60_degree_screw.burgers):.2f} Angstrom")

Si_60_degree_screw.view_cyl(Si_60_degree_screw_dislo, scale=0.3, add_bonds=True,
                            line_color=[0, 0, 1])
Cell vectors:
[[46.56069608  0.          0.        ]
 [ 0.         47.03340562  0.        ]
 [ 0.          0.          3.84026149]]

Burgers vector length: 3.84 Angstrom
Si_60_degree_screw_bulk, \
Si_60_degree_screw_dislo = Si_60_degree_screw.build_cylinder(radius=20, 
                                                             partial_distance=5)

print(f"Expected partial distance: {5 * Si_60_degree_screw.glide_distance:.1f} Angstrom")
Si_60_degree_screw.view_cyl(Si_60_degree_screw_dislo, scale=0.3, add_bonds=True, 
                                line_color=[[1, 0, 1], [0, 1, 1]])
Expected partial distance: 16.6 Angstrom