Twinning Analysis

Explains how to detect and quantify twin boundaries

On this page ...
Data import and grain detection
Properties of grain boundaries
Merge twins along twin boundaries
Grain relationships
Calculate the twinned area
Setting Up the EBSD Data for the Merged Grains

Data import and grain detection

Lets import some Magnesium data that are full of grains and segment grain within the data set.

% load some example data
mtexdata twins

% segment grains
[grains,ebsd.grainId,ebsd.mis2mean] = calcGrains(ebsd('indexed'),'angle',5*degree);

% remove two pixel grains
ebsd(grains(grains.grainSize<=2)) = [];
[grains,ebsd.grainId,ebsd.mis2mean] = calcGrains(ebsd('indexed'),'angle',5*degree);

% smooth them
grains = grains.smooth(5);

% visualize the grains

% store crystal symmetry of Magnesium
CS = grains.CS;
  I'm going to colorize the orientation data with the 
  standard MTEX colorkey. To view the colorkey do:
  oM = ipfColorKey(ori_variable_name)

Now we can extract from the grains its boundary and save it to a separate variable

gB = grains.boundary
gB = grainBoundary  
 Segments   mineral 1  mineral 2
      600  notIndexed  Magnesium
     3164   Magnesium  Magnesium

The output tells us that we have 3219 Magnesium to Magnesium boundary segments and 606 boundary segements where the grains are cut by the scanning boundary. To restrict the grain boundaries to a specific phase transistion you shall do

gB_MgMg = gB('Magnesium','Magnesium')
gB_MgMg = grainBoundary  
 Segments  mineral 1  mineral 2
     3164  Magnesium  Magnesium

Properties of grain boundaries

A variable of type grain boundary contains the following properties

These can be used to colorize the grain boundaries. By the following command, we plot the grain boundaries colorized by the misorientation angle


We observe many grain boundaries with a large misorientation angle of about 86 degrees. Those grain boundaries are most likely twin boundaries. To detect them more precisely we define first the twinning as a misorientation, which is reported in literature by (1,1,-2,0) parallel to (2,-1,-1,0) and (-1,0,1,1) parallel to (1,0,-1,1). In MTEX it is defined by

twinning =,1,-2,0,CS),Miller(2,-1,-1,0,CS),...
twinning = misorientation  
  size: 1 x 1
  crystal symmetry : Magnesium (6/mmm, X||a*, Y||b, Z||c*)
  crystal symmetry : Magnesium (6/mmm, X||a*, Y||b, Z||c*)
  Bunge Euler angles in degree
  phi1     Phi    phi2    Inv.
   330 93.6529     330       0

The followin lines show that the twinning is actually a rotation about axis (-2110) and angle 86.3 degree

% the rotational axis

% the rotational angle
twinning.angle / degree
ans = Miller  
 size: 1 x 1
 mineral: Magnesium (622, X||a*, Y||b, Z||c*)
  h -1
  k  2
  i -1
  l  0
ans =

Next, we check for each boundary segment whether it is a twinning boundary, i.e., whether boundary misorientation is close to the twinning.

% restrict to twinnings with threshold 5 degree
isTwinning = angle(gB_MgMg.misorientation,twinning) < 5*degree;
twinBoundary = gB_MgMg(isTwinning)

% plot the twinning boundaries
hold on
plot(twinBoundary,'linecolor','w','linewidth',2,'displayName','twin boundary')
hold off
twinBoundary = grainBoundary  
 Segments  mineral 1  mineral 2
     1649  Magnesium  Magnesium
  I'm going to colorize the orientation data with the 
  standard MTEX colorkey. To view the colorkey do:
  oM = ipfColorKey(ori_variable_name)

Merge twins along twin boundaries

Grains that have a common twin boundary are assumed to inherite from one common grain. To reconstruct those initial grains we merge grains together which have a common twin boundary. This is done by the command merge.

[mergedGrains,parentId] = merge(grains,twinBoundary);

% plot the merged grains
hold on
  'displayName','merged grains')
hold off

Grain relationships

The second output argument paraentId of merge is a list with the same size as grains which indicates for each grain into which common grain it has been merged. The id of the common grain is usually different from the ids of the merged grains and can be found by

ans =

Hence, we can find all childs of grain 16 by

childs = grains(parentId == mergedGrains(16).id)
childs = grain2d  
 Phase  Grains  Pixels    Mineral  Symmetry  Crystal reference frame
     1       8    1698  Magnesium     6/mmm       X||a*, Y||b, Z||c*
 boundary segments: 442
 triple points: 25
 Id   Phase   Pixels          GOS   phi1   Phi   phi2
  6       1       40   0.00752395    178    90    236
 14       1      254    0.0113434     81    25    187
 17       1        4    0.0135723     80    26    189
 19       1       38   0.00595743     95   145    186
 24       1      774    0.0102947    178    90    235
 28       1       45    0.0107243     81    26    188
 29       1      293   0.00910428     94   146    185
 33       1      250    0.0106861    179    89    235

Calculate the twinned area

We can also answer the question about the relative area of these initial grains that have undergone twinning to total area.

twinId = unique(gB_MgMg(isTwinning).grainId);

% compute the area fraction
sum(area(grains(twinId))) / sum(area(grains)) * 100
ans =

Setting Up the EBSD Data for the Merged Grains

Note that the Id's of the merged grains does not fit the grainIds stored in the initial ebsd variable. As a consequence, the following command will not give the right result

hold on
hold off

In order to update the grainId in the ebsd variable to the merged grains, we proceed as follows.

% copy ebsd data into a new variable to not change the old data
ebsd_merged = ebsd;

% update the grainIds to the parentIds
ebsd_merged('indexed').grainId = parentId(ebsd('indexed').grainId)
ebsd_merged = EBSD  
 Phase  Orientations     Mineral       Color  Symmetry  Crystal reference frame
     0     46 (0.2%)  notIndexed                                               
     1  22794 (100%)   Magnesium  light blue     6/mmm       X||a*, Y||b, Z||c*
 Properties: bands, bc, bs, error, mad, x, y, grainId, mis2mean
 Scan unit : um

Now the variable ebsd_merged can be indexed by the merged grains, i.e.

hold on
hold off