Geometrically Necessary Dislocations edit page

A spatial change in lattice orientation requires dislocations to preserve compatibility. These are geometrically necessary dislocations (GNDs). Conventional two-dimensional EBSD measures only the in-plane orientation gradient, so it cannot identify a unique three-dimensional dislocation population.

The workflow on this page follows Pantleon (2008). It computes the measured lattice curvature and fits the least-energy combination of candidate dislocation systems that reproduces it. Read Dislocation Systems first for the Burgers vector, line vector, tensor basis, and relative line-energy weights used here.

Load and segment the map

The example is a ferritic steel map after two percent uniaxial deformation. The 'minPixel' option marks indexed regions smaller than six pixels as notIndexed during segmentation. A 2.5 degree threshold separates the remaining grains.

plottingConvention.default('y←↑x');
ebsd = EBSD.load([mtexDataPath filesep 'EBSD' filesep ...
  'DC06_2uniax.ang'],'setting',2);

[grains,ebsd] = calcGrains(ebsd,'angle',2.5*degree,'minPixel',6);
grains = smoothBoundary(grains,5);

An inverse pole figure (IPF) key colors each indexed orientation by the crystal direction parallel to specimen \(y\). The boundaries provide the spatial context for the orientation changes used below.

ipfKey = ipfHSVKey(ebsd);
ipfKey.ipfDirection = yvector;

plot(ebsd,ipfKey.orientation2color(ebsd.orientations), ...
  'refFrame','on','figSize','medium')
hold on
plot(grains.boundary,'linewidth',2)
hold off

Notice that each grain has a dominant color, while smaller color changes remain inside many grains. Those intragranular changes carry the curvature signal, together with measurement noise.

Denoise before differentiating

Differentiation amplifies point-to-point orientation noise and therefore overestimates GND density. An axis-angle color key makes local departures from each grain's mean orientation easier to see before filtering.

axisKey = axisAngleColorKey(ebsd);
axisKey.oriRef = grains(ebsd('indexed').grainId).meanOrientation;

plot(ebsd('indexed'), ...
  axisKey.orientation2color(ebsd('indexed').orientations), ...
  'micronBar','off','figSize','medium')
hold on
plot(grains.boundary,'linewidth',2)
hold off

The pixel-scale color speckle is the symptom to notice. A halfQuadraticFilter reduces that noise while the 'fill' option uses the grain partition to prevent smoothing across grain boundaries.

F = halfQuadraticFilter;
ebsd = smooth(ebsd,F,'fill',grains);

axisKey.oriRef = grains(ebsd('indexed').grainId).meanOrientation;
plot(ebsd('indexed'), ...
  axisKey.orientation2color(ebsd('indexed').orientations), ...
  'micronBar','off','figSize','medium')
hold on
plot(grains.boundary,'linewidth',2)
hold off

The denoised map retains broad color gradients inside grains but suppresses much of the isolated pixel-to-pixel variation. Filtering is therefore part of the measurement model, not merely cosmetic preparation for the plot.

Estimate GND content in one command

Ferrite is body-centred cubic, so this example uses the standard BCC set of 48 edge and 4 screw systems. Following the normalization on the preceding page, the edge weight is one and the screw weight is \(1-\nu\), with Poisson's ratio \(\nu=0.3\).

There is no universally accepted set of line-energy weights. Replace these illustrative values with values appropriate to the material and model.

dS = dislocationSystem.bcc(ebsd.CS);
nu = 0.3;
dS(dS.isEdge).u = 1;
dS(dS.isScrew).u = 1 - nu;

calcGND returns an energy-weighted GND density for each pixel and the signed density assigned to each candidate system. The first output is often called the total dislocation energy. With the dimensionless weights above, it is an energy-weighted density rather than an absolute energy measurement.

[gnd,rho] = calcGND(ebsd,dS);

close all
plot(ebsd,gnd,'micronbar','off')
mtexColorMap('hot')
mtexColorbar
set(gca,'ColorScale','log'); % requires MATLAB R2018a or newer
set(gca,'CLim',[1e11 5e14]);
hold on
plot(grains.boundary,'linewidth',2)
hold off

Read the map on its logarithmic scale. Bright regions require a larger energy-weighted dislocation content to reproduce the measured curvature; dark regions require less. Grain boundaries are overlaid for location, but the fitted values belong to EBSD pixels rather than boundary segments.

The maths behind the workflow

The remainder of the page expands the operations performed by calcGND. This sequence is useful when you need to inspect tensor components, change the candidate systems, or retain their individual fitted densities.

Compute the incomplete curvature tensor

The curvature tensor \(\boldsymbol\kappa\) collects directional derivatives of lattice orientation. A two-dimensional map supplies derivatives along its two in-plane directions but not along the map normal.

kappaMeasured = ebsd.curvature
kappaMeasured = curvatureTensor (y←↑x)
  size: 101 × 51 
  unit: 1/um     
  rank: 2 (3 × 3)

Inspect one pixel and one component. Curly braces select a tensor component over the whole map, whereas parentheses select map positions.

kappaMeasured(3,2)
kappa12 = kappaMeasured{1,2};
size(kappa12)
ans = curvatureTensor (y←↑x)
  unit: 1/um     
  rank: 2 (3 × 3)
 
 *10^-5
   4.28 -27.46    NaN
   7.96 -61.91    NaN
  57.48 -30.84    NaN
ans =
   101    51

The component array has the same size as the EBSD map. For this scan the unknown out-of-plane derivative occupies the third tensor column, so that column contains NaN.

newMtexFigure('nrows',3,'ncols',3);
for i = 1:3
  for j = 1:3
    nextAxis(i,j)
    plot(ebsd,kappaMeasured{i,j},'micronBar','off')
    hold on
    plot(grains.boundary,'linewidth',2)
    hold off
  end
end
setColorRange([-0.005,0.005])
drawNow(gcm,'figSize','large')

Read columns from left to right in each tensor row. The blank panels in the third column make the unmeasured out-of-plane derivative explicit; they are not zero-curvature components.

Convert curvature to the Nye tensor

Nye's dislocation-density tensor \(\boldsymbol\alpha\) is related to curvature by

\[ \boldsymbol\alpha = \boldsymbol\kappa^{T} - \mathrm{tr}(\boldsymbol\kappa)\,\mathbf I. \]

The method dislocationDensity applies this relation.

alphaMeasured = kappaMeasured.dislocationDensity
alphaMeasured(3,2)
alphaMeasured = dislocationDensityTensor (y←↑x)
  size: 101 × 51 
  unit: 1/um     
  rank: 2 (3 × 3)
 
ans = dislocationDensityTensor (y←↑x)
  unit: 1/um     
  rank: 2 (3 × 3)
 
 *10^-5
    NaN   7.96  57.48
 -27.46    NaN -30.84
    NaN    NaN  57.63

This tensor remains incomplete because the map contains no derivative normal to its plane. MTEX can recover the \((3,3)\) entry from the two known diagonal curvature components, but the other missing entries remain NaN.

Rotate the candidate systems

Each tensor supplied by dS.tensor is the rank-two dyad \(\mathbf b\otimes\hat{\mathbf l}\). Its length unit is inherited from the unit cell, usually Angstrom and displayed as au.

The tensors are initially expressed in the crystal frame. The measured curvature is expressed in the specimen frame, so each pixel orientation must rotate all candidate systems into that same frame.

dS(1).tensor
dSRot = ebsd.orientations * dS;
ans = dislocationDensityTensor (Iron (Alpha))
  unit: au       
  rank: 2 (3 × 3)
 
 -1.1717 -0.5858  0.5858
  1.1717  0.5858 -0.5858
 -1.1717 -0.5858  0.5858

Fit individual system densities

fitDislocationSystems solves a linear program at every pixel. It reproduces the six measured curvature components while minimizing \(\sum_j u_j\lvert\rho_j\rvert\) over the candidate systems.

The Optimization Toolbox function linprog is required. The result rho has one row per EBSD pixel and one column per dislocation system. Its signs distinguish the two line senses represented internally during the fit.

[rhoWorked,factor] = fitDislocationSystems(kappaMeasured,dSRot);
size(rhoWorked)
factor
ans =
        5151          52
factor =
   1.0000e+16

The scale factor converts the density coefficients from \(1/(\mathrm{\mu m}\,\mathrm{au})\) to \(1/\mathrm{m}^2\). With micrometre scan units and Angstrom lattice units it is \(10^{16}\).

Reconstruct the fitted tensors

Sum each rotated basis tensor multiplied by its fitted density. The numeric matrix rhoWorked does not retain units, so the tensor unit must be restored explicitly after this manual reconstruction.

alphaFitted = reshape(sum(dSRot.tensor .* rhoWorked,2),size(ebsd));
alphaFitted.opt.unit = '1/um';

alphaFitted(3,2)
kappaMeasured(3,2).dislocationDensity
ans = dislocationDensityTensor (y←↑x)
  unit: 1/um     
  rank: 2 (3 × 3)
 
 *10^-5
  59.13   7.96  57.48
 -27.46  -7.06 -30.84
  12.66  -9.03  57.63
 
ans = dislocationDensityTensor (y←↑x)
  unit: 1/um     
  rank: 2 (3 × 3)
 
 *10^-5
    NaN   7.96  57.48
 -27.46    NaN -30.84
    NaN    NaN  57.63

The fitted tensor is complete because the chosen dislocation population supplies the components that EBSD cannot measure directly. Converting it back gives a complete fitted curvature tensor.

kappaFitted = alphaFitted.curvature
kappaFitted(3,2)

newMtexFigure('nrows',3,'ncols',3);
for i = 1:3
  for j = 1:3
    nextAxis(i,j)
    plot(ebsd,kappaFitted{i,j},'micronBar','off')
    hold on
    plot(grains.boundary,'linewidth',2)
    hold off
  end
end
setColorRange([-0.005,0.005])
drawNow(gcm,'figSize','large');
kappaFitted = curvatureTensor (y←↑x)
  size: 101 × 51 
  unit: 1/um     
  rank: 2 (3 × 3)
 
ans = curvatureTensor (y←↑x)
  unit: 1/um     
  rank: 2 (3 × 3)
 
 *10^-5
   4.28 -27.46  12.66
   7.96 -61.91  -9.03
  57.48 -30.84   2.78

Unlike the measured grid, this grid has values in all nine panels. The fitted in-plane columns reproduce the observations; the third column is a model-dependent completion, not an additional EBSD measurement.

Reproduce the one-command result

Multiplying the absolute fitted densities by their line-energy weights and by the unit factor gives the scalar returned by calcGND.

gndWorked = factor * sum(abs(rhoWorked .* dSRot.u),2);
max(abs(gndWorked-gnd),[],'omitnan')
ans =
     0

The zero difference verifies that the expanded sequence and calcGND use the same calculation. Plotting the worked result therefore reproduces the first GND map.

close all
plot(ebsd,gndWorked,'micronbar','off')
mtexColorMap('hot')
mtexColorbar
set(gca,'ColorScale','log'); % requires MATLAB R2018a or newer
set(gca,'CLim',[1e11 5e14]);
hold on
plot(grains.boundary,'linewidth',2)
hold off

References

Next

Continue with Weighted Burgers Vector for a boundary-based measure of lattice-curvature content that does not fit a complete population of crystallographic dislocation systems.

Citing this page. This page is part of the documentation of MTEX, a free and open source MATLAB toolbox for analyzing and modeling crystallographic textures. It was written by The MTEX Developers and is published at https://mtex-toolbox.github.io/GND.html. If you use MTEX, or reuse text or figures from this page, in your research, please cite

F. Bachmann, R. Hielscher, H. Schaeben: Texture Analysis with MTEX - Free and Open Source Software Toolbox, Solid State Phenomena 160 (2010), 63-68. 10.4028/www.scientific.net/SSP.160.63

BibTeX
@article{bachmann2010mtex,
  author  = {F. Bachmann and R. Hielscher and H. Schaeben},
  title   = {Texture Analysis with MTEX - Free and Open Source Software Toolbox},
  journal = {Solid State Phenomena},
  volume  = {160},
  pages   = {63-68},
  year    = {2010},
  doi     = {10.4028/www.scientific.net/SSP.160.63},
  url     = {https://doi.org/10.4028/www.scientific.net/SSP.160.63}
}

Other papers describing specific MTEX methods are listed under Publications — please cite the one that best fits your application. The MTEX source code is licensed under the GNU General Public License v2.0; the text and figures of this documentation are licensed under CC BY 4.0, which permits reuse — including by automated systems — provided The MTEX Developers and this page are credited.