# Working with Grains

How to index grains and access shape properties.

 On this page ... Accessing individual grains Indexing by a Condition Indexing by orientation or position Grain-size Analysis Spatial Dependencies

Grains have several intrinsic properties, which can be used for statistical, shape as well as for spatial analysis

Let us first import some EBSD data and reconstruct grains

```plotx2east
mtexdata forsterite
ebsd = ebsd(inpolygon(ebsd,[5 2 10 5]*10^3));
grains = calcGrains(ebsd)

plot(ebsd)
hold on
plot(grains.boundary,'linewidth',2)
hold off```
```
grains = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
0    1139    4052  notIndexed
1     242   14093  Forsterite       mmm
2     177    1397   Enstatite       mmm
3     104     759    Diopside     12/m1       X||a*, Y||b*, Z||c

boundary segments: 10420
triple points: 903

Properties: GOS, meanRotation

```

## Accessing individual grains

The variable grains is essentially a large vector of grains. Thus when applying a function like area to this variable we obtain a vector of the same lenght with numbers representing the area of each grain

`grain_area = grains.area;`

As a first rather simple application we could colorize the grains according to their area, i.e., according to the numbers stored in grain_area

`plot(grains,grain_area)`

As a second application, we can ask for the largest grain within our data set. The maximum value and its position within a vector are found by the Matlab command max.

`[max_area,max_id] = max(grain_area)`
```max_area =
3.8945e+06
max_id =
1617
```

The number max_id is the position of the grain with a maximum area within the variable grains. We can access this specific grain by direct indexing

`grains(max_id)`
```
ans = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
1       1    1548  Forsterite       mmm

boundary segments: 424
triple points: 70

Id   Phase   Pixels         GOS   phi1   Phi   phi2
1617       1     1548   0.0129383    167    81    251

```

and so we can plot it

```hold on
plot(grains(max_id).boundary,'linecolor','red','linewidth',1.5)
hold off```

Note that this way of addressing individual grains can be generalized to many grains. E.g. assume we are interested in the largest 5 grains. Then we can sort the vector grain_area and take the indices of the 5 largest grains.

```[sorted_area,sorted_id] = sort(grain_area,'descend');

large_grain_id = sorted_id(1:5);

hold on
plot(grains(large_grain_id).boundary,'linecolor','green','linewidth',1.5)
hold off```

## Indexing by a Condition

By the same syntax as above we can also single out grains that satisfy a certain condition. I.e., to access are grains that are at least half as large as the largest grain we can do

```condition = grain_area > max_area/2;

hold on
plot(grains(condition).boundary,'linecolor','red','linewidth',1.5)
hold off```

This is a very powerful way of accessing grains as the condition can be build up using any grain property. As an example let us consider the phase. The phase of the first five grains we get by

`grains(1:5).phase`
```ans =
0
0
0
0
2
```

Now we can access or grains of the first phase Forsterite by the condition

```condition = grains.phase == 1;
plot(grains(condition))```

To make the above more directly you can use the mineral name for indexing

`grains('forsterite')`
```
ans = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
1     242   14093  Forsterite       mmm

boundary segments: 7670
triple points: 795

Properties: GOS, meanRotation

```

Logical indexing allows also for more complex queries, e.g. selecting all grains perimeter larger than 6000 and at least 600 measurements within

```condition = grains.perimeter>6000 & grains.grainSize >= 600;

selected_grains = grains(condition)

plot(selected_grains)```
```
selected_grains = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
1       5    5784  Forsterite       mmm

boundary segments: 1893
triple points: 244

Id   Phase   Pixels          GOS   phi1   Phi   phi2
798       1     1447     0.013232    166   127    259
876       1     1075   0.00805971    153    68    237
999       1     1044   0.00753116     89    99    224
1617       1     1548    0.0129383    167    81    251
1620       1      670    0.0870135    143    78    274

```

## Indexing by orientation or position

One can also select a grain by its spatial coordinates using the syntax grains(x,y)

```x = 12000; y = 4000;

plot(grains);

hold on

plot(grains(x,y).boundary,'linewidth',2,'linecolor','r')

plot(x,y,'marker','s','markerfacecolor','k',...
'markersize',10,'markeredgecolor','w')
hold off```

In order to select all grains with a certain orientation one can do

```% restrict first to Forsterite phase
grains_fo = grains('fo')

% the reference orientation
ori = orientation.byEuler(350*degree,50*degree,100*degree,grains('fo').CS)

% select all grain with misorientation angle to ori less then 20 degree
grains_selected = grains_fo(angle(grains_fo.meanOrientation,ori)<20*degree)

plot(grains_selected)```
```
grains_fo = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
1     242   14093  Forsterite       mmm

boundary segments: 7670
triple points: 795

Properties: GOS, meanRotation

ori = orientation
size: 1 x 1
crystal symmetry : Forsterite (mmm)
specimen symmetry: 1

Bunge Euler angles in degree
phi1  Phi phi2 Inv.
350   50  100    0

grains_selected = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
1      12    2979  Forsterite       mmm

boundary segments: 1603
triple points: 173

Id   Phase   Pixels          GOS   phi1   Phi   phi2
359       1       63    0.0129176    177   140    250
389       1        1            0    167   128    260
622       1      352   0.00896432    153   122    252
636       1      305    0.0156453    164   115    268
680       1      331    0.0198713    152   143    247
798       1     1447     0.013232    166   127    259
1297       1      289    0.0315393    166   147    260
1549       1        1            0      1    47    279
1609       1       48    0.0169152    158   139    259
1629       1       10    0.0193004    172   125    261
1660       1      129   0.00814837      1    47    279
1662       1        3   0.00475795      1    47    279

```

## Grain-size Analysis

Let's go back to the grain size and analyze its distribution. To this end, we consider the complete data set.

```mtexdata forsterite
% consider only indexed data for grain segmentation
ebsd = ebsd('indexed');
% perform grain segmentation
[grains,ebsd.grainId] = calcGrains(ebsd)```
```
grains = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
1    1080  152345  Forsterite       mmm
2     515   26058   Enstatite       mmm
3    1496    9064    Diopside     12/m1       X||a*, Y||b*, Z||c

boundary segments: 43912
triple points: 3417

Properties: GOS, meanRotation

ebsd = EBSD

Phase  Orientations     Mineral        Color  Symmetry  Crystal reference frame
1  152345 (81%)  Forsterite   light blue       mmm
2   26058 (14%)   Enstatite  light green       mmm
3   9064 (4.8%)    Diopside    light red     12/m1       X||a*, Y||b*, Z||c

Properties: bands, bc, bs, error, mad, x, y, grainId
Scan unit : um

```

Then the following command gives you a nice overview over the grain size distributions of the grains

`hist(grains)`

Sometimes it is desirable to remove all boundary grains as they might distort grain statistics. To do so one should remember that each grain boundary has a property grainId which stores the ids of the neigbouring grains. In the case of an outer grain boundary, one of the neighbouring grains has the id zero. We can filter out all these boundary segments by

```% ids of the outer boundary segment
outerBoundary_id = any(grains.boundary.grainId==0,2);

plot(grains)
hold on
plot(grains.boundary(outerBoundary_id),'linecolor','red','linewidth',2)
hold off```

Now grains.boundary(outerBoundary_id).grainId is a list of grain ids where the first column is zero, indicating the outer boundary, and the second column contains the id of the boundary grain. Hence, it remains to remove all grains with these ids.

```% next we compute the corresponding grain_id
grain_id = grains.boundary(outerBoundary_id).grainId;

% remove all zeros
grain_id(grain_id==0) = [];

% and plot the boundary grains
plot(grains(grain_id))```

finally, we can remove the boundary grains by

```grains(grain_id) = []

plot(grains)```
```
grains = grain2d

Phase  Grains  Pixels     Mineral  Symmetry  Crystal reference frame
1     968  116882  Forsterite       mmm
2     480   23877   Enstatite       mmm
3    1467    8871    Diopside     12/m1       X||a*, Y||b*, Z||c

boundary segments: 40105
triple points: 3383

Properties: GOS, meanRotation

```

Beside the area, there are various other geometric properties that can be computed for grains, e.g., the perimeter, the diameter, the equivalentRadius, the equivalentPerimeter, the aspectRatio, and the shapeFactor. The following is a simple scatter plot of shape factor against aspect ratio to check for correlation.

```% the size of the dots corresponds to the area of the grains
close all
scatter(grains.shapeFactor, grains.aspectRatio, 70*grains.area./max(grains.area))```
`plot(grains,log(grains.aspectRatio))`

## Spatial Dependencies

One interesting question would be, whether a polyphase system has dependence in the spatial arrangement or not, therefore, we can count the transitions to a neighbour grain

`%[J, T, p ] = joinCount(grains,grains.phase)`