Merging grains may be usefull when reconstructing parent grain structures, i.e., before phase transistion or before twinning. In this section we will use a twinning example for illustration. Lets start by importing some Magenesium data and reconstructing the grain structure:
% load some example data
mtexdata twins silent
% 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,'removeQuadruplePoints');
% smooth them
grains = grains.smooth(5);
% visualize the grains
plot(grains,grains.meanOrientation)

Next we identify all twinning boundaries
% define twinning misorientation
CS = grains.CS;
twinning = orientation.map(Miller(0,1,-1,-2,CS),Miller(0,-1,1,-2,CS),...
Miller(2,-1,-1,0,CS),Miller(2,-1,-1,0,CS));
% extract all Magnesium Magnesium grain boundaries
gB = grains.boundary('Magnesium','Magnesium');
% and check which of them are twinning boundaries with threshold 5 degree
isTwinning = angle(gB.misorientation,twinning) < 5*degree;
twinBoundary = gB(isTwinning)
% plot the twinning boundaries
hold on
plot(twinBoundary,'linecolor','w','linewidth',4,'displayName','twin boundary')
hold off
twinBoundary = grainBoundary
Segments length mineral 1 mineral 2
1649 361 µm Magnesium Magnesium

Merge grains along boundaries
The command merge will merge grains together that have a commong boundary which is specified as the second argument. In our example we want to merge all grains that have a common twinning boundary so we do
[mergedGrains,parentId] = merge(grains,twinBoundary);
% plot the merged grains
hold on
plot(mergedGrains.boundary,'linecolor','k','linewidth',2.5,'linestyle','-',...
'displayName','merged grains')
hold off

Grain relationships
The second output argument paraentId
of merge is a list with the same size as the child grains which indicates for each child grain into which parent 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
mergedGrains(16).id
ans =
16
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 (103 µm)
inner boundary segments: 0 (0 µm)
triple points: 25
Id Phase Pixels phi1 Phi phi2 GOS
6 1 40 178 90 236 0.00755032
14 1 254 81 25 187 0.0113603
17 1 4 80 26 189 0.0135724
19 1 38 95 145 186 0.00600972
24 1 774 178 90 235 0.0102946
28 1 45 80 25 188 0.0108147
29 1 293 94 145 185 0.00913161
33 1 250 179 89 235 0.0107513
Estimate twin area fraction
Determining which of the measured grains are orginal grains and which are twins is a tough problem. Here we make a very simple assumption by labeling those areas as twins that make up less than half of the merged (original) parent grain
% extract grain area for faster access
gArea = grains.area;
% loop over mergedGrains and determine children that are not twins
isTwin = true(grains.length,1);
for i = 1:mergedGrains.length
% get child ids
childId = find(parentId==i);
% cluster grains of similar orientations
[fId,center] = calcCluster(grains.meanOrientation(childId),'maxAngle',...
15*degree,'method','hierarchical','silent');
% compute area of each cluster
clusterArea = accumarray(fId,gArea(childId));
% label the grains of largest cluster as original grain
[~,fParent] = max(clusterArea);
isTwin(childId(fId==fParent)) = false;
end
% compute the area fraction of twins
sum(area(grains(isTwin)))/sum(area(grains)) * 100
% visualize the result
close all
plot(grains(~isTwin),'FaceColor','darkgray','displayName','not twin')
hold on
plot(grains(isTwin),'FaceColor','red','displayName','twin')
hold on
plot(mergedGrains.boundary,'linecolor','k','linewidth',2,'linestyle','-',...
'displayName','merged grains')
mtexTitle('twin id')
ans =
16.6212

The parentId
may also be used to compute properties of the parent grains by averaging over the corresponding child grain properties. This can be done with the Matlab command accumarray
% this averages the GOS of the child grains into the parent grains
mergedGrains.prop.GOS = accumarray(parentId,grains.GOS,size(mergedGrains),@nanmean);
% visualize the result
close all
plot(grains,grains.GOS ./ degree)
hold on
plot(mergedGrains.boundary,'lineColor','white','lineWidth',2)
mtexTitle('original GOS')
mtexColorbar
nextAxis
plot(mergedGrains,mergedGrains.GOS ./ degree)
mtexTitle('merged GOS')
mtexColorbar
caxis([0,1.5])

The above result is a bit unrealistic since the averages are computed between the childs ignoring their relative areas. A better approach is to compute a weighted average by the following lines.
% extract GOS and area
childGOS = grains.GOS;
childArea = grains.area;
% compute the weighted averages
mergedGrains.prop.GOS = accumarray(parentId,1:length(grains),size(mergedGrains),...
@(id) nanmeanWeights(childGOS(id),childArea(id)));
nextAxis(2), hold on
plot(mergedGrains,mergedGrains.GOS ./ degree)
setColorRange equal
mtexColorbar
caxis([0,1.5])

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
close all
plot(mergedGrains(16).boundary,'linewidth',2)
hold on
plot(ebsd(mergedGrains(16)),ebsd(mergedGrains(16)).orientations)
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(grains.id2ind(ebsd('indexed').grainId))
ebsd_merged = EBSD
Phase Orientations Mineral Color Symmetry Crystal reference frame
0 46 (0.2%) notIndexed
1 22794 (100%) Magnesium LightSkyBlue 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.
plot(ebsd_merged(mergedGrains(16)),ebsd_merged(mergedGrains(16)).orientations)
hold on
plot(mergedGrains(16).boundary,'linewidth',2)
hold off
