download as script · edit page

A triple point is a junction where exactly three grain boundary segments meet and separate three distinct real grains. It is therefore a strict subset of the junctions in a boundary network. An endpoint at the scan rim is a junction, for example, but it is not a triple point.

MTEX computes triple points automatically during grain reconstruction. They are available from a grain list through grains.triplePoints, just as the boundary segments are available through grains.boundary. The result is a triplePointList.

A square measurement grid can also produce vertices where four boundary segments meet. When analysing triple points, it is a good idea to pass removeQuadruplePoints to calcGrains. This converts each ambiguous quadruple point into two triple points. Quadruple Points explains the resulting topology.

This page assumes that the map has already been divided into grains as in Grain Reconstruction. Select Grain Boundaries introduces boundary-list indexing, and Boundary Misorientations explains the disorientations used below.

import numpy as np
from mtex import *
# load the example map in its specimen plotting frame
plottingConvention.default('y↑→x')
ebsd = mtexdata('small')

# reconstruct the grains and resolve quadruple points
grains = calcGrains(ebsd, removeQuadruplePoints=True, alpha=5)

# smooth the pixel staircase while keeping junctions fixed
grains = smoothBoundary(grains, 2)

# draw the grains and overlay all triple points
plot(grains)
tP = grains.triplePoints
hold(True)
plot(tP, color='b', lineWidth=2)
hold(False)
tP
triplePointList (y↑→x)
  size: 68
  points   mineral 1   mineral 2   mineral 3
      14  Forsterite  Forsterite  Forsterite
       7  Forsterite  Forsterite   Enstatite
       9  Forsterite  Forsterite    Diopside
       4  Forsterite   Enstatite   Enstatite
      16  Forsterite   Enstatite    Diopside
       4  Forsterite    Diopside    Diopside
       2   Enstatite   Enstatite    Diopside
       1   Enstatite    Diopside    Diopside
      11    Diopside    Diopside    Diopside

The blue circles lie only where three real grains meet. They do not mark loose ends at the map rim or every crossing in the boundary network.

Select by phase

Phase names select triple points by the phases of their three adjacent grains. Repeating a name requests that multiplicity; the names do not assign an order to the three sides. One name therefore means at least one adjacent forsterite grain.

tP['Forsterite']
triplePointList (y↑→x)
  size: 54
  points   mineral 1   mineral 2   mineral 3
      14  Forsterite  Forsterite  Forsterite
       7  Forsterite  Forsterite   Enstatite
       9  Forsterite  Forsterite    Diopside
       4  Forsterite   Enstatite   Enstatite
      16  Forsterite   Enstatite    Diopside
       4  Forsterite    Diopside    Diopside

Repeating the name selects points with at least two adjacent forsterite grains.

tP['Forsterite', 'Forsterite']
triplePointList (y↑→x)
  size: 30
  points   mineral 1   mineral 2   mineral 3
      14  Forsterite  Forsterite  Forsterite
       7  Forsterite  Forsterite   Enstatite
       9  Forsterite  Forsterite    Diopside

Three repeated names restrict the selection to inner diopside triple points, where all three adjacent grains are diopside.

hold(True)
plot(tP['Diopside', 'Diopside', 'Diopside'], displayName='Di-Di-Di', color='darkred', lineWidth=2)
hold(False)

The dark-red circles are a subset of the blue points. Their locations show where the diopside boundary network branches entirely within that phase.

Select by grain

A triple point also belongs to each of its three adjacent grains. A grain selection therefore returns the points on the boundary of that grain.

# find the list position of the largest grain
largestIndex = int(np.argmax(grains.area))

# extract and plot the triple points of that grain
tP_largest = grains[largestIndex].triplePoints
plot(grains[largestIndex], faceColor=[0.2, 0.8, 0.8], displayName='largest grain')
hold(True)
plot(grains.boundary)
plot(tP_largest, color='r', lineWidth=2)
hold(False)

The red circles occur only where the cyan grain meets two other grains. The black network supplies the surrounding context that a grain outline alone would hide.

Select through grain boundaries

Triple points are also stored with a grainBoundary selection. Here the eligible segments are first restricted to forsterite–forsterite boundaries, so every disorientation has one consistent phase pair.

# all forsterite--forsterite boundary segments
gB_Fo = grains.boundary['Forsterite', 'Forsterite']
gB_Fo
grainBoundary (y↑→x)
  size: 217 segments, 36 chains
  segments    length   mineral 1   mineral 2
       217  10014 µm  Forsterite  Forsterite

# retain segments whose disorientation angle is larger than 60 degrees
gB_large = gB_Fo[gB_Fo.misorientation.angle() > 60 * degree]
gB_large
grainBoundary (y↑→x)
  size: 46 segments, 15 chains
  segments   length   mineral 1   mineral 2
        46  2103 µm  Forsterite  Forsterite

# plot those segments and every triple point incident to at least one of them
plot(grains)
hold(True)
plot(gB_large, lineWidth=2, lineColor='w')
plot(gB_large.triplePoints, color='m', lineWidth=2)
hold(False)

White marks the selected high-angle segments. A magenta circle means that at least one selected segment reaches that point; it does not mean that all three incident segments exceed 60 degrees.

Boundary segments at a triple point

The boundaryId property has one row per triple point and three columns for its incident segments. These values index the complete boundary list from which the triple points came. Here all three neighbouring grains are first restricted to forsterite.

# select forsterite--forsterite--forsterite triple points
tP_Fo = grains.triplePoints['Fo', 'Fo', 'Fo']

# extract the three incident boundary segments for every selected point
gB = grains.boundary[tP_Fo.boundaryId]

# plot the incident segments
plot(grains)
hold(True)
plot(gB, lineColor='w', lineWidth=2)
hold(False)

The white three-armed groups are the local boundary neighbourhoods of the selected points. Use tP_Fo.boundaryId.ravel() when a single list of segments is wanted instead of this point-by-segment arrangement.

Disorientations around the point

The same indexing extracts the disorientation across each incident segment. The displayed object has size \(n \times 3\), where \(n\) is the number of selected triple points.

mori = gB.misorientation
mori
misorientation (Forsterite → Forsterite)
  size     : 14 × 3
  antipodal: true
  Bunge Euler angles in degree
  phi1   Phi  phi2
   132  18.6   239
  2.13   146   353
   154   154   161
    69  6.44   316
   179  60.6   180
     ⋮     ⋮     ⋮
   292   121   299
  60.9  56.3   260
   116  38.9  60.6
   251   120  96.9
   127   141   135

A simple scalar summary is the sum of the three disorientation angles at each point.

sumMisAngle = np.sum(mori.angle(), axis=1)

plot(grains, figSize='large')
hold(True)
plot(tP_Fo, sumMisAngle / degree, markerEdgeColor='w', markerSize=8)
hold(False)
mtexColorMap('blue2red')
setColorRange([80, 180])
mtexColorbar()

Colour records that angle sum in degrees. The fixed colour range saturates any sum above 180 degrees at its upper colour. This scalar is descriptive, not a crystallographic closure condition. The underlying ordered rotations close around the three grains, but their three minimum disorientation angles do not generally add to a fixed value.

Section angles at triple points

The property tP.angles returns the three angles enclosed by the incident boundary segments. It is an \(n \times 3\) matrix, and each row sums to \(2\pi\). The spread between the largest and smallest angle measures how unequal the three arms appear in this two-dimensional section.

tP = grains.triplePoints
angleSpread = (np.max(tP.angles, axis=1) - np.min(tP.angles, axis=1)) / degree

plot(grains, figSize='large')
hold(True)
plot(tP, angleSpread, markerEdgeColor='w', markerSize=8)
hold(False)
mtexColorMap('LaboTeX')
setColorRange([0, 180])
mtexColorbar()

Pale points have three more nearly equal section angles, while dark-red points have a larger angular spread. These are angles between smoothed traces in the section, not the full dihedral angles of three boundary planes in three dimensions.

In a section perpendicular to the three-dimensional junction line, equal, orientation-independent boundary energies at local equilibrium would give three 120 degree angles. Unequal energies, anisotropy, drag, non-equilibrium microstructure, sectioning, and segmentation can all move the observed values away from that ideal. The angle spread must therefore not be read directly as a boundary-energy measurement.

Further reading

Next

Continue with Quadruple Points for the grid ambiguity resolved at reconstruction. CSL Boundaries classifies triple points by the character of their incident boundaries. Merging Grains then shows how selected boundaries alter the grains and their junction network. For full boundary-plane geometry, continue to 3D EBSD. Triple points also supply local orientation evidence in Triple Point Based Reconstruction of parent grains.

Technical Details

A tuple of phase names in brackets selects triple points, MATLAB’s tP('Forsterite','Forsterite'). At MATLAB’s default of 15 degrees the port finds 68 triple points where MATLAB finds 70, the 14 between three forsterite grains as MATLAB’s, and 217 forsterite boundary segments for MATLAB’s 220: the not indexed third of this map is closed by the neighbouring grains a little differently, and alpha does not change the closing here, as Grain Reconstruction says.

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/TriplePoints_py.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.