orientation gradient along the two lattice directions
Works on any EBSD - a plain list, a phase subset, a gridified map - by placing every pixel on the virtual lattice ebsd.lattice derives from the unit cell, so it needs neither a matrix layout nor an axis aligned grid. A rotated or sheared grid is handled by the same code.
Description
Three stencils are available. All of them skip a neighbour that is not comparable - outside the map, notIndexed, a different phase, or across a grain boundary where grainId is known.
'oneSided' (default) takes the neighbour at +a_k, and falls back to -a_k (negated) only where +a_k lies outside the map. A missing neighbour inside the map yields NaN and does NOT fall back, which is what the matrix based EBSDsquare/gradient1 does and what keeps existing GND / WBV numbers unchanged. This is why it stays the default: the other two move every number that depends on the gradient.
'1hop' is a least squares fit over the lattice's own neighbour stencil, ebsd.lattice.stencil - the 4 axial neighbours of a square grid, the 6 neighbours of a hex one. Symmetric, and in the interior of a square grid exactly the central difference.
'full' is the same fit over all eight offsets in {-1,0,1}^2, i.e. the 1-hop stencil plus the diagonals. On a square grid that is the full 8 neighbourhood; on a hex grid it adds the two second nearest neighbours along a1+a2. Still symmetric, and better conditioned - a pixel needs two independent directions to be solvable at all, so the wider stencil leaves far fewer pixels NaN (18 against 374 on forsterite). The fit uses each neighbour's true physical offset, so mixing the two distances is handled correctly, but note it does weight every neighbour equally rather than by distance.
Before MTEX 7 'leastSquares' used a hardcoded six offset list on every grid. That is the hex stencil, and on a square grid it is 4 axial plus TWO of the four diagonals - an asymmetric neighbourhood which biased the fit along one diagonal, by up to 0.042 (mean 0.0009) on forsterite. Its comment claimed those offsets did not exist on a square lattice; they do.
Syntax
g = gradient(ebsd) % one sided (default)
g = gradient(ebsd,'stencil','oneSided') % the same, explicitly
g = gradient(ebsd,'stencil','1hop') % least squares, 1-hop stencil
g = gradient(ebsd,'stencil','full') % least squares, full stencil
g = gradient(ebsd,'leastSquares') % alias for 'stencil','1hop'
g = gradient(ebsd,'basis',[a1 a2]) % use an explicit basis
[g,A] = gradient(ebsd)Input
| ebsd | EBSD |
Output
| g | length(ebsd) x 2 vector3d, g(:,k) = d(orientation) / d(a_k), in the left tangent space, i.e. log(ori(p+a_k),ori(p))/|a_k| |
| A | 2 x 2 basis actually used, columns a1, a2 (map plane components) |
Options
| stencil | which neighbours the gradient is computed from, see below |
| basis | 1x2 vector3d, use these as (a1,a2) instead of the ones derived from the unit cell |
Flags
| leastSquares | alias for |'stencil','1hop'| |