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")
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)
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.000700298380692771
disloc SCF 1 |d1-d2|_inf = 0.0003518249861800271
disloc SCF 2 |d1-d2|_inf = 0.00017675440092204675
disloc SCF 3 |d1-d2|_inf = 8.880016897094833e-05
disloc SCF 4 |d1-d2|_inf = 4.4612580869296536e-05
disloc SCF 5 |d1-d2|_inf = 2.2413047115033002e-05
disloc SCF 6 |d1-d2|_inf = 1.1260157359860301e-05
disloc SCF 7 |d1-d2|_inf = 5.657023923660853e-06
disloc SCF 8 |d1-d2|_inf = 2.842049061868579e-06
disloc SCF 9 |d1-d2|_inf = 1.4278254745203611e-06
disloc SCF 10 |d1-d2|_inf = 7.173294832574229e-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.08751883578065112
disloc SCF 1 |d1-d2|_inf = 0.040861196124220456
disloc SCF 2 |d1-d2|_inf = 0.022825263559017622
disloc SCF 3 |d1-d2|_inf = 0.013827362573782587
disloc SCF 4 |d1-d2|_inf = 0.008309453605806982
disloc SCF 5 |d1-d2|_inf = 0.004949366223313545
disloc SCF 6 |d1-d2|_inf = 0.002920835307407388
disloc SCF 7 |d1-d2|_inf = 0.0017075894224892751
disloc SCF 8 |d1-d2|_inf = 0.0009889006148836588
disloc SCF 9 |d1-d2|_inf = 0.0005672574174527822
disloc SCF 10 |d1-d2|_inf = 0.0003222508524111656
disloc SCF 11 |d1-d2|_inf = 0.00018124374430711354
disloc SCF 12 |d1-d2|_inf = 0.00010087332160257922
disloc SCF 13 |d1-d2|_inf = 5.551627821182015e-05
disloc SCF 14 |d1-d2|_inf = 3.0181880222024393e-05
disloc SCF 15 |d1-d2|_inf = 1.618533490022056e-05
disloc SCF 16 |d1-d2|_inf = 8.543846241548803e-06
disloc SCF 17 |d1-d2|_inf = 4.426490513853576e-06
disloc SCF 18 |d1-d2|_inf = 2.241008178083259e-06
disloc SCF 19 |d1-d2|_inf = 1.1012012559041828e-06
disloc SCF 20 |d1-d2|_inf = 5.193489804877771e-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.1456039707936726
disloc SCF 1 |d1-d2|_inf = 0.05990757346454212
disloc SCF 2 |d1-d2|_inf = 0.028503341908167393
disloc SCF 3 |d1-d2|_inf = 0.014419391826501756
disloc SCF 4 |d1-d2|_inf = 0.007081941950075079
disloc SCF 5 |d1-d2|_inf = 0.0033683464731162106
disloc SCF 6 |d1-d2|_inf = 0.0015423024365131474
disloc SCF 7 |d1-d2|_inf = 0.0007171164954147269
disloc SCF 8 |d1-d2|_inf = 0.0005234232461244215
disloc SCF 9 |d1-d2|_inf = 0.0003433121906488701
disloc SCF 10 |d1-d2|_inf = 0.00021084706513296858
disloc SCF 11 |d1-d2|_inf = 0.0001235904716112568
disloc SCF 12 |d1-d2|_inf = 6.984771376106202e-05
disloc SCF 13 |d1-d2|_inf = 3.8278349353770835e-05
disloc SCF 14 |d1-d2|_inf = 2.0405799376455036e-05
disloc SCF 15 |d1-d2|_inf = 1.0596408768215326e-05
disloc SCF 16 |d1-d2|_inf = 5.359853928021963e-06
disloc SCF 17 |d1-d2|_inf = 2.6369154058070166e-06
disloc SCF 18 |d1-d2|_inf = 1.2576923436036225e-06
disloc SCF 19 |d1-d2|_inf = 5.781284193595582e-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.12800570244558904
disloc SCF 1 |d1-d2|_inf = 0.0611628318013856
disloc SCF 2 |d1-d2|_inf = 0.03322894295246637
disloc SCF 3 |d1-d2|_inf = 0.018834010903773735
disloc SCF 4 |d1-d2|_inf = 0.010317674555603257
disloc SCF 5 |d1-d2|_inf = 0.005479968807368271
disloc SCF 6 |d1-d2|_inf = 0.0028203538962095903
disloc SCF 7 |d1-d2|_inf = 0.001401658703759856
disloc SCF 8 |d1-d2|_inf = 0.00066783326952434
disloc SCF 9 |d1-d2|_inf = 0.00030095624285221556
disloc SCF 10 |d1-d2|_inf = 0.00012483600670443185
disloc SCF 11 |d1-d2|_inf = 7.214731613247594e-05
disloc SCF 12 |d1-d2|_inf = 5.1322790716401556e-05
disloc SCF 13 |d1-d2|_inf = 3.3733459126050747e-05
disloc SCF 14 |d1-d2|_inf = 2.100906770152733e-05
disloc SCF 15 |d1-d2|_inf = 1.2556644481076518e-05
disloc SCF 16 |d1-d2|_inf = 7.252149701209021e-06
disloc SCF 17 |d1-d2|_inf = 4.06244776751663e-06
disloc SCF 18 |d1-d2|_inf = 2.210578465611235e-06
disloc SCF 19 |d1-d2|_inf = 1.168236141602108e-06
disloc SCF 20 |d1-d2|_inf = 6.090321289786704e-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.14861912042082293
disloc SCF 1 |d1-d2|_inf = 0.06368262746234343
disloc SCF 2 |d1-d2|_inf = 0.031187863915750756
disloc SCF 3 |d1-d2|_inf = 0.015754979395605516
disloc SCF 4 |d1-d2|_inf = 0.007773687670121765
disloc SCF 5 |d1-d2|_inf = 0.0037396753216583645
disloc SCF 6 |d1-d2|_inf = 0.001747333337163856
disloc SCF 7 |d1-d2|_inf = 0.0007877019555048714
disloc SCF 8 |d1-d2|_inf = 0.0003678175708667908
disloc SCF 9 |d1-d2|_inf = 0.0002595603858459583
disloc SCF 10 |d1-d2|_inf = 0.00016731771283673424
disloc SCF 11 |d1-d2|_inf = 0.00010183918931794267
disloc SCF 12 |d1-d2|_inf = 5.948393096422144e-05
disloc SCF 13 |d1-d2|_inf = 3.364317526766136e-05
disloc SCF 14 |d1-d2|_inf = 1.8522886038763176e-05
disloc SCF 15 |d1-d2|_inf = 9.958811746813012e-06
disloc SCF 16 |d1-d2|_inf = 5.237887889641968e-06
disloc SCF 17 |d1-d2|_inf = 2.69686160958571e-06
disloc SCF 18 |d1-d2|_inf = 1.3589880438757973e-06
disloc SCF 19 |d1-d2|_inf = 6.694323611000641e-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.02222081473347748
disloc SCF 1 |d1-d2|_inf = 0.0107739038928778
disloc SCF 2 |d1-d2|_inf = 0.005185027906170286
disloc SCF 3 |d1-d2|_inf = 0.002475082781572324
disloc SCF 4 |d1-d2|_inf = 0.0011712409716692074
disloc SCF 5 |d1-d2|_inf = 0.0005491236463884552
disloc SCF 6 |d1-d2|_inf = 0.00025489205141415727
disloc SCF 7 |d1-d2|_inf = 0.00011703200541879344
disloc SCF 8 |d1-d2|_inf = 5.3085397455437944e-05
disloc SCF 9 |d1-d2|_inf = 2.5718688654030597e-05
disloc SCF 10 |d1-d2|_inf = 1.2808643933992503e-05
disloc SCF 11 |d1-d2|_inf = 6.3685165325733095e-06
disloc SCF 12 |d1-d2|_inf = 3.161062653966873e-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.15473510917799427
disloc SCF 1 |d1-d2|_inf = 0.06777415250108643
disloc SCF 2 |d1-d2|_inf = 0.034754392948041016
disloc SCF 3 |d1-d2|_inf = 0.018101177738677476
disloc SCF 4 |d1-d2|_inf = 0.008961495147710302
disloc SCF 5 |d1-d2|_inf = 0.004180664619767474
disloc SCF 6 |d1-d2|_inf = 0.001795819982429496
disloc SCF 7 |d1-d2|_inf = 0.0013438620432928428
disloc SCF 8 |d1-d2|_inf = 0.0009841068440423761
disloc SCF 9 |d1-d2|_inf = 0.0006551466763722313
disloc SCF 10 |d1-d2|_inf = 0.00040906842714139025
disloc SCF 11 |d1-d2|_inf = 0.00024307855806582346
disloc SCF 12 |d1-d2|_inf = 0.00013844319756362022
disloc SCF 13 |d1-d2|_inf = 7.578385209117133e-05
disloc SCF 14 |d1-d2|_inf = 3.98508356251881e-05
disloc SCF 15 |d1-d2|_inf = 2.005030802476604e-05
disloc SCF 16 |d1-d2|_inf = 9.56585079980865e-06
disloc SCF 17 |d1-d2|_inf = 4.656306369636709e-06
disloc SCF 18 |d1-d2|_inf = 2.498681741021358e-06
disloc SCF 19 |d1-d2|_inf = 1.2860867572156431e-06
disloc SCF 20 |d1-d2|_inf = 6.310074034815427e-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.06447946338433506
disloc SCF 1 |d1-d2|_inf = 0.033452469764595524
disloc SCF 2 |d1-d2|_inf = 0.017489485207730526
disloc SCF 3 |d1-d2|_inf = 0.009570765143307236
disloc SCF 4 |d1-d2|_inf = 0.005227931148117371
disloc SCF 5 |d1-d2|_inf = 0.002848373595293885
disloc SCF 6 |d1-d2|_inf = 0.00161338836180374
disloc SCF 7 |d1-d2|_inf = 0.0009239710238140783
disloc SCF 8 |d1-d2|_inf = 0.000525519825772966
disloc SCF 9 |d1-d2|_inf = 0.00029702134945678443
disloc SCF 10 |d1-d2|_inf = 0.00016691081798440172
disloc SCF 11 |d1-d2|_inf = 9.32994713160884e-05
disloc SCF 12 |d1-d2|_inf = 5.189687352652461e-05
disloc SCF 13 |d1-d2|_inf = 2.8735088627565575e-05
disloc SCF 14 |d1-d2|_inf = 1.584204152624974e-05
disloc SCF 15 |d1-d2|_inf = 8.69829299404018e-06
disloc SCF 16 |d1-d2|_inf = 4.757294939330969e-06
disloc SCF 17 |d1-d2|_inf = 2.5921033584216935e-06
disloc SCF 18 |d1-d2|_inf = 1.407212705341332e-06
disloc SCF 19 |d1-d2|_inf = 7.612349909591476e-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