Skip to content

Commit

Permalink
Merge pull request #244 from thomas-rocke/DislocKink
Browse files Browse the repository at this point in the history
WIP: Disloc kink structure generation
  • Loading branch information
jameskermode authored Sep 13, 2024
2 parents 6809af7 + 8da8bdb commit 260ee3a
Show file tree
Hide file tree
Showing 11 changed files with 1,612 additions and 372 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
- name: pytest
run: |
cd tests
pytest -v --junitxml=report.xml --durations=20
pytest -v --junitxml=report.xml --durations=20 --timeout=300
- name: report
uses: mikepenz/action-junit-report@v4
Expand Down
343 changes: 343 additions & 0 deletions docs/applications/disloc_mobility.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Modelling the Mobility of Dislocations with `matscipy`\n",
"The dislocation modelling toolkit provided in `matscipy.dislocation` includes functions to assist in characterising the mobility of dislocations in various systems. Currently, only motion in the glide direction is supported.\n",
"\n",
"## Dislocation Glide\n",
"Dislocation Glide is where the dislocation line migrates in the glide direction. There are two main mechanisms for attempting to describe dislocation glide dynamics.\n",
"\n",
"The first mechanism is the (double) kink mechanism. Starting from a perfectly straight dislocation line, a small segment nucleates out in the glide directionforming a pair of dislocation kinks. These kinks can then migrate along the dislocation line.\n",
"\n",
"A second, simpler mechanism is to consider the entire dislocation line moving at once - this is much less physical than the double kink mechanism, but can be a good first approximation. The 2D nature of this mechanism can also make it much simpler to study, rather than having to deal with the fully 3D kinks.\n",
"\n",
"\n",
"### Glide in Dislocation Cylinders\n",
"As an example of modelling dislocation glide in cylindrical cells, let's look at the Diamond Screw dislocation in Si, using the [Holland and Marder](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.80.746) potential:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from matscipy.dislocation import get_elastic_constants, DiamondGlide60Degree\n",
"# the calculator to provide forces and energies from the potential\n",
"from matscipy.calculators.manybody.explicit_forms.stillinger_weber import StillingerWeber,\\\n",
" Holland_Marder_PRL_80_746_Si\n",
"from matscipy.calculators.manybody import Manybody\n",
"calc = Manybody(**StillingerWeber(Holland_Marder_PRL_80_746_Si))\n",
"\n",
"# the function accepts any ASE type of calculator\n",
"alat, C11, C12, C44 = get_elastic_constants(calculator=calc, symbol=\"Si\", verbose=False)\n",
"\n",
"Si_disloc = DiamondGlide60Degree(alat, C11, C12, C44, symbol=\"Si\")\n",
"\n",
"Si_disloc_bulk, Si_disloc_dislo = Si_disloc.build_cylinder(radius=20)\n",
"Si_disloc.view_cyl(Si_disloc_dislo, mode=\"dxa\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To generate the initial and final structures for a full glide event, we can use the `build_glide_configurations` function. The structures contain straight dislocation lines, separated by the dislocation glide distance. These structures will be similar to those produced by a call to `build_cylinder`, except extra bulk is added (creating a pill shape, not a circle) in order to make the initial and final configurations symmetric.\n",
"\n",
"We can also then use the `ase.neb` tools to smoothly interpolate an approximate glide path, which allows us to generate structures for the simpler dislocation glide mechanism discussed above."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"bulk, glide_ini, glide_fin = Si_disloc.build_glide_configurations(radius=20)\n",
"\n",
"from ase.neb import NEB\n",
"\n",
"nims = 5\n",
"\n",
"glide_neb = NEB([glide_ini.copy() for i in range(nims-1)] + [glide_fin.copy()])\n",
"\n",
"glide_neb.interpolate(method=\"idpp\", apply_constraint=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To visualise the glide structures, we will combine ase's `plot_atoms` to convert a structure to a matplotlib plot, and then use FuncAnimation to animate the glide structures: "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def animate_glide(images, diamond=True, radii=None):\n",
" from ase.visualize.plot import plot_atoms\n",
" import matplotlib.pyplot as plt\n",
" from matplotlib.animation import FuncAnimation\n",
" from matscipy.utils import get_structure_types\n",
" from visualisation import show_HTML\n",
"\n",
" fig, ax = plt.subplots(figsize=(10, 10))\n",
" ax.axis(\"off\")\n",
"\n",
" # Add extra reps of start and end points for clarity\n",
" anim_images = [images[0]] * 3 + images + [images[-1]] * 3\n",
"\n",
" def plot_frame(framedata):\n",
" ax.clear()\n",
" # Plot an individual frame of the animation \n",
" framenum, atoms = framedata\n",
"\n",
" # get CNA colours to enhance plot\n",
" atom_labels, struct_names, colors = get_structure_types(atoms, \n",
" diamond_structure=diamond)\n",
" atom_colors = [colors[atom_label] for atom_label in atom_labels]\n",
"\n",
" plot_atoms(atoms, ax=ax, colors=atom_colors, radii=radii)\n",
"\n",
"\n",
" animation = FuncAnimation(fig, plot_frame, frames=enumerate(anim_images),\n",
" save_count=len(anim_images),\n",
" init_func=lambda: None,\n",
" interval=200)\n",
" \n",
" # Need to convert animation to HTML in order for it to be visible on the docs\n",
" return show_HTML(animation)\n",
"\n",
"animate_glide(glide_neb.images, radii=0.3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is also possible in the dissociated case:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"bulk, glide_ini, glide_fin = Si_disloc.build_glide_configurations(radius=20, partial_distance=5)\n",
"\n",
"nims = 5\n",
"\n",
"glide_neb = NEB([glide_ini.copy() for i in range(nims-1)] + [glide_fin.copy()])\n",
"\n",
"glide_neb.interpolate(method=\"idpp\", apply_constraint=True)\n",
"\n",
"animate_glide(glide_neb.images, radii=0.3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Glide in Dislocation Quadrupoles\n",
"As quadrupoles are extremely useful for modelling dislocations using plane-wave DFT, it can be convenient to be able to set up initial guesses for complex processes such as dislocation glide.\n",
"\n",
"We can use the function `build_glide_quadrupoles` to construct a set of images for this system, which can optionally model the glide of either the \"left\" ($+\\mathbf{b}$) or \"right\" ($-\\mathbf{b}$) dislocation cores, or both at once."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from matscipy.dislocation import Quadrupole\n",
"\n",
"Si_quad = Quadrupole(DiamondGlide60Degree, alat, C11, C12, C44, symbol=\"Si\")\n",
"\n",
"num_images = 5\n",
"\n",
"glide_quads = Si_quad.build_glide_quadrupoles(nims=num_images, \n",
" glide_left=True, # Allow left dislocation glide\n",
" glide_right=True, # Allow right dislocation glide\n",
" glide_separation=6,\n",
" verbose=False)\n",
"\n",
"animate_glide(glide_quads)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"num_images = 5\n",
"\n",
"glide_quads = Si_quad.build_glide_quadrupoles(nims=num_images, \n",
" glide_left=False, # Prevent left dislocation glide\n",
" glide_right=True, # Allow right dislocation glide\n",
" partial_distance=2, # Dissociated Glide\n",
" glide_separation=8,\n",
" verbose=False)\n",
"\n",
"animate_glide(glide_quads)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dislocation Kink\n",
"Dislocation kink is often the preferred mechanism for migration of the dislocation line. It involves a short segment of the dislocation line hopping by one glide vector, which then provides a low barrier for the rest of the dislocation line to migrate.\n",
"\n",
"Here the space of structures to explore is greater, due to the 3D nature of dislocation kink. Kink nucleation is also possible on segments of an already kinked-out dislocation line, which can lead to a full network of dislocation kinks. \n",
"\n",
"### Kink maps\n",
"Dislocation kink in `matscipy` is controlled by a kink map, which controls the position of the dislocation line as a function of the vertical coordinate. The kink map is a list of integers, where the values give a line position in units of glide distances, and each element corresponds to an extra cell in z (replication of `disloc.unit_cell`).\n",
"\n",
"A kink map of `[0, 0, 1, 1]` means that the dislocation line initially starts at position zero for two repetitions, and then moves out by one glide distance for two repetitions.\n",
"\n",
"Both dislocation cylinders and quadrupoles have support for this kind of kink map, but the periodic boundaries are treated differently. \n",
"\n",
"In dislocation cylinders (using `build_kink_cyl`), the periodicity in z is enforced by requiring that the dislocation line returns back to the initial position across the periodic boundary. The example kink map of `[0, 0, 1, 1]` will therefore have a single kink out in the center of the cell, and a single kink back at the periodic boundary (the dislocation line will go like `0, 0, 1, 1, 0, 0, 1, 1, ...`).\n",
"\n",
"In quadrupoles (using `build_kink_quadrupole_network`), the cell is modified such that the dislocation position at the top of the cell becomes the new dislocation line position at the bottom of the cell. This means that for quadrupoles an extra kink will not be created, and that the example map of `[0, 0, 1, 1]` will create only one kink in the center of the cell.\n",
"\n",
":::{note}\n",
"For the cell shift to always produce the correct crystalstructure, some atoms need to be deleted for some values of `kink_map[-1]`. This means that some kink maps may not conserve stoichiometry for some multispecies systems.\n",
":::\n",
"\n",
"Since the kink map is just a list of integers, it can be more convenient to exploit list addition, and specify kink maps in a form similar to `[0] * 5 + [1] * 5`, which would be identical to the input of `[0, 0, 0, 0, 0, 1, 1, 1, 1, 1]`.\n",
"\n",
"### Kink in cylinders"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Si_bulk, Si_kink = Si_disloc.build_kink_cylinder(\n",
" radius=20,\n",
" kink_map= [0] * 5 + [1] * 5\n",
" )\n",
"\n",
"Si_disloc.view_cyl(Si_kink)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Kink in quadrupoles\n",
"Like with dislocation cylinders, we can build networks of kinks in dislocation quadrupoles:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Si_quad_bulk, Si_quad_kink = Si_quad.build_kink_quadrupole(\n",
" glide_separation=8,\n",
" kink_map=[0]*5 + [1]*5,\n",
" verbose=False\n",
")\n",
"\n",
"Si_quad.view_quad(Si_quad_kink, mode=\"dxa\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There is also another routine `build_minimal_kink_quadrupole` for building only the smallest possible kink structures. This is where the kink happens in a single burgers vector cell. Here, the `n_kink` parameter controls the number of glide distances covered by the kink, and the direction of the kink: `n_kink=2` builds a compressed version of the kink map `[0, 2]`, and `n_kink=-1` constructs a compressed version of `[0, -1]`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Si_quad_bulk, Si_quad_kink = Si_quad.build_minimal_kink_quadrupole(\n",
" glide_separation=8,\n",
" n_kink=1,\n",
" verbose=False\n",
")\n",
"\n",
"Si_quad.view_quad(Si_quad_kink, mode=\"dxa\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Improving the kink structures\n",
"So far, we have only used the Continuum Linear Elastic (CLE) solutions when building kink structures. As the kink structures are built by interpolating between glide structures, we can get a better approximation of the kink if we relax these glide structures before building the kink. \n",
"\n",
"To do this, we can replace a call to `build_kink_cylinder` with a call to `build_kink_glide_structs` to build the required glide structures, and then `build_kink_from_glide_cyls` to actually construct the kink. For quadrupoles, the equivalent is replacing `build_kink_quadrupole` with `build_kink_quadrupole_glide_structs` and `build_kink_quadrupole_from_glide_structs`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from matscipy.calculators.manybody.explicit_forms.stillinger_weber import StillingerWeber,\\\n",
" Holland_Marder_PRL_80_746_Si\n",
"from matscipy.calculators.manybody import Manybody\n",
"from ase.optimize.precon import PreconLBFGS\n",
"\n",
"\n",
"calc = Manybody(**StillingerWeber(Holland_Marder_PRL_80_746_Si))\n",
"\n",
"kink_map = [0] * 5 + [1] * 5\n",
"\n",
"ref_bulk, glide_structs, struct_map = Si_disloc.build_kink_glide_structs(kink_map, radius=40)\n",
"\n",
"# glide_structs has a length of 2, as only two unique values in the kink map\n",
"\n",
"for struct in glide_structs:\n",
" struct.calc = calc\n",
" opt = PreconLBFGS(struct, logfile=None)\n",
" opt.run(1e-1)\n",
"\n",
"Si_bulk, Si_kink = Si_disloc.build_kink_from_glide_cyls(ref_bulk, glide_structs, struct_map)\n",
"\n",
"Si_disloc.view_cyl(Si_kink)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
4 changes: 3 additions & 1 deletion docs/applications/multispecies_dislocations.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@
"\n",
"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. \n",
"\n",
"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."
":::{note}\n",
"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 dislocation classes.\n",
":::"
]
},
{
Expand Down
5 changes: 3 additions & 2 deletions docs/applications/plasticity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ Tutorials:
----------

.. toctree::

cylinder_configurations.ipynb
multispecies_dislocations.ipynb
quadrupole_dislocations.ipynb
disloc_mobility.ipynb
multispecies_dislocations.ipynb
gamma_surfaces.ipynb
gamma_surface_advanced.ipynb
Loading

0 comments on commit 260ee3a

Please sign in to comment.