Grain Data

To study the microstructure-properties relationship for polycrystalline materials, collecting morphological and physical properties of the grains constituting a microstructure is an important task, that complements the study of microstructure images. This tutorial will review how to store, load and process grain data with Pymicro.

In the Microstructure class data model, the GrainData group is aimed at storing statistical data describing the sample grains, that are mostly stored within a structured array, the GrainDataTable.

One of Pymicro’s example datasets will be used to study this group. Let’s start by opening it with the Microstructure class and display the content of this group:

[1]:
from pymicro import get_examples_data_dir # import file directory path
PYMICRO_EXAMPLES_DATA_DIR = get_examples_data_dir() # get the file directory path
import os

# import Microstructure class
from pymicro.crystal.microstructure import Microstructure
micro = Microstructure(filename=os.path.join(PYMICRO_EXAMPLES_DATA_DIR,'t5_dct_slice_data.h5'))

# display CellData group content
micro.print_node_info('GrainData')
micro.print_group_content('GrainData', short=True)

 GROUP GrainData
=====================
 -- Parent Group : /
 -- Group attributes :
         * group_type : Data
 -- Childrens : GrainDataTable,
----------------

     --NODE GrainDataTable: /GrainData/GrainDataTable (structured_array) (    1.464 Kb)

The Grain Data Table

The GrainDataTable mentioned above is the only data item stored in the GrainData group in the standard data model of the Microstructure class. Let’s take a look at its content:

[2]:
print(type(micro['GrainDataTable']))
print(micro['GrainDataTable'].dtype)
print(micro['GrainDataTable'])
<class 'numpy.ndarray'>
[('bounding_box', '<i4', (3, 2)), ('center', '<f4', (3,)), ('idnumber', '<i4'), ('orientation', '<f4', (3,)), ('volume', '<f4'), ('phase', 'u1')]
[([[257, 498], [131, 334], [  0,   1]], [ 0.06535962, -0.13540885,  0.        ],   1, [ 0.09452096,  0.45667315, -0.1908928 ], 9.7096439e-05, 1)
 ([[131, 382], [361, 537], [  0,   1]], [-0.08418886,  0.1768474 ,  0.        ],   3, [ 0.47176334,  0.42443925,  0.21837033], 7.6571319e-05, 1)
 ([[169, 321], [171, 375], [  0,   1]], [-0.12312692, -0.07267088,  0.        ],   5, [ 0.7891136 , -0.56843024,  0.01993851], 4.3942415e-05, 1)
 ([[328, 523], [311, 469], [  0,   1]], [ 0.14214575,  0.08379043,  0.        ],   6, [ 0.5407849 , -0.5829121 , -0.15143125], 5.3993688e-05, 1)
 ([[105, 156], [301, 420], [  0,   1]], [-0.27974364,  0.04052933,  0.        ],   7, [-0.4113469 ,  0.18637992, -0.0899675 ], 1.0572632e-05, 1)
 ([[415, 566], [131, 189], [  0,   1]], [ 0.22478512, -0.24323939,  0.        ],   9, [-0.22051871, -0.568544  , -0.26730168], 1.4035560e-05, 1)
 ([[467, 569], [245, 391], [  0,   1]], [ 0.27332932, -0.01910632,  0.        ],  10, [ 0.7321588 ,  0.4550985 , -0.1540665 ], 2.9939783e-05, 1)
 ([[142, 249], [291, 415], [  0,   1]], [-0.19227512,  0.04570894,  0.        ],  14, [-0.8053556 ,  0.5361014 ,  0.011616  ], 2.5060952e-05, 1)
 ([[109, 212], [458, 539], [  0,   1]], [-0.24462087,  0.24956882,  0.        ],  16, [-0.79714507, -0.36815822, -0.23475127], 1.3780368e-05, 1)
 ([[106, 237], [132, 214], [  0,   1]], [-0.22398418, -0.22145346,  0.        ],  17, [ 0.0384308 , -0.5491175 ,  0.08449803], 2.2212680e-05, 1)
 ([[104, 172], [211, 312], [  0,   1]], [-0.26658773, -0.09434833,  0.        ],  18, [ 0.05181912,  0.9767362 , -0.23218708], 1.5297799e-05, 1)
 ([[335, 448], [454, 540], [  0,   1]], [ 0.09969319,  0.24543414,  0.        ],  22, [-0.18012922,  0.6727327 ,  0.25471398], 1.7715263e-05, 1)
 ([[320, 323], [343, 348], [  0,   1]], [-0.0077    ,  0.0259    ,  0.        ],  25, [ 0.15638582,  0.884963  , -0.22157212], 5.4879998e-09, 1)
 ([[441, 553], [447, 539], [  0,   1]], [ 0.2280725 ,  0.24248306,  0.        ],  32, [ 0.5988454 , -0.38010532, -0.08003835], 1.8077471e-05, 1)
 ([[499, 574], [388, 516], [  0,   1]], [ 0.29737142,  0.16697936,  0.        ],  37, [-0.7061676 ,  0.36509004,  0.0142626 ], 1.5863065e-05, 1)
 ([[484, 567], [160, 249], [  0,   1]], [ 0.283409  , -0.16862918,  0.        ],  40, [ 0.0959702 ,  0.6410337 , -0.0187812 ], 1.5026144e-05, 1)
 ([[237, 304], [133, 179], [  0,   1]], [-0.08731515, -0.24403782,  0.        ],  51, [ 0.62000704, -0.2996727 ,  0.11647069], 5.2163441e-06, 1)
 ([[106, 133], [402, 467], [  0,   1]], [-0.29301223,  0.15198556,  0.        ],  52, [ 0.5636417 , -0.5580199 , -0.15464744], 3.4574400e-06, 1)
 ([[553, 571], [358, 396], [  0,   1]], [ 0.33029434,  0.07187878,  0.        ],  98, [ 0.13639925,  0.8033593 ,  0.13590527], 1.1634560e-06, 1)
 ([[243, 266], [366, 386], [  0,   1]], [-0.1045768 ,  0.06894867,  0.        ], 115, [-0.86381924,  0.441323  , -0.05843058], 7.2167200e-07, 1)
 ([[104, 115], [194, 221], [  0,   1]], [-0.30526504, -0.1671011 ,  0.        ], 124, [-0.6494284 ,  0.26412636,  0.16653858], 5.0215198e-07, 1)]

### Get values from the GrainDataTable

The GrainDataTable stores a structured table, that can be retrieved as a Numpy structured array. As shown below, its fields provide the following information on the sample grains:

  • an identity number of the grain

  • two columns describing the grain geometry: volume and center (position of center of mass in sample)

  • the orientation of the grain provided as a Rodrigues vector

  • the indices of the grain bounding box in the CellData image field arrays

To retrieve those values, you can use standard manipulation commands for SampleData structured tables and numpy arrays (see dedicated tutorial), or dedicated Microstructure class methods, such as get_grain_centers:

  • get_grain_centers

  • get_grain_bounding_boxes

  • get_grain_volumes

[3]:
import numpy as np

# retrieve table as numpy structured array with SampleData dictionary like access
GrainDataTable = micro['GrainDataTable']

# get table columns from class methods and compare to arrays got with numpy array manipulation
grain_ids = micro.get_grain_ids()
print(f'grain ids equal ? {np.all(grain_ids == GrainDataTable["idnumber"])}')
grain_centers = micro.get_grain_centers()
print(f'grain centers equal ? {np.all(grain_centers == GrainDataTable["center"])}')
grain_volumes = micro.get_grain_volumes()
print(f'grain volumes equal ? {np.all(grain_volumes == GrainDataTable["volume"])}')
grain_bboxes = micro.get_grain_bounding_boxes()
print(f'grain bounding boxes equal ? {np.all(grain_bboxes == GrainDataTable["bounding_box"])}')
grain_rodrigues = micro.get_grain_rodrigues()
print(f'grain orientations equal ? {np.all(grain_rodrigues == GrainDataTable["orientation"])}')
grain ids equal ? True
grain centers equal ? True
grain volumes equal ? True
grain bounding boxes equal ? True
grain orientations equal ? True

Other methods to get specific grain data are also available in the class interface:

[4]:
centers = micro.get_grain_positions()
print(f'The position of the 10 first grain centers of mass are:\n {centers[:10]}\n')

volume_fractions = micro.get_grain_volume_fractions()
print(f'The 10 first grain volume fractions are:\n {volume_fractions[:10]}\n')

volume_fr = micro.get_grain_volume_fraction(18)
print(f'Volume fraction of grain 18 is {volume_fr*100:1.3f}%')
The position of the 10 first grain centers of mass are:
 [[ 0.06535962 -0.13540885  0.        ]
 [-0.08418886  0.1768474   0.        ]
 [-0.12312692 -0.07267088  0.        ]
 [ 0.14214575  0.08379043  0.        ]
 [-0.27974364  0.04052933  0.        ]
 [ 0.22478512 -0.24323939  0.        ]
 [ 0.27332932 -0.01910632  0.        ]
 [-0.19227512  0.04570894  0.        ]
 [-0.24462087  0.24956882  0.        ]
 [-0.22398418 -0.22145346  0.        ]]

The 10 first grain volume fractions are:
 [0.20217805 0.15943983 0.09149864 0.11242779 0.02201475 0.0292254
 0.0623418  0.05218291 0.02869403 0.04625212]

Volume fraction of grain 18 is 3.185%

The grains attribute

The Microstructure.grains attribute is an alias for the GrainDataTable data item. As such, it allows to manipulate and interact directly with the GrainDataTable. You can use it to access grain data just like you would manipulate a Numpy structured array:

[5]:
print(micro.grains[0]['center'],'\n')
print(micro.grains[4:10]['orientation'])
[ 0.06535962 -0.13540885  0.        ]

[[-0.4113469   0.18637992 -0.0899675 ]
 [-0.22051871 -0.568544   -0.26730168]
 [ 0.7321588   0.4550985  -0.1540665 ]
 [-0.8053556   0.5361014   0.011616  ]
 [-0.79714507 -0.36815822 -0.23475127]
 [ 0.0384308  -0.5491175   0.08449803]]

Hence, getting an information on a grain whose id number is known, can be done with a call of the form micro.grains["idnumber"]['"information"'].

Iterate Grains

The GrainDataTable can also be iterated. The iteration is done row by row of the structured array, and the iterator return these rows during a for loop:

[6]:
# iterate through grains with ID number below 200 and print center of masss
for g in micro.grains:
    if g["idnumber"] > 100:
        break
    print(f'Grain {g["idnumber"]} center of mass is located at {g["center"]}')
Grain 1 center of mass is located at [ 0.06535962 -0.13540885  0.        ]
Grain 3 center of mass is located at [-0.08418886  0.1768474   0.        ]
Grain 5 center of mass is located at [-0.12312692 -0.07267088  0.        ]
Grain 6 center of mass is located at [0.14214575 0.08379043 0.        ]
Grain 7 center of mass is located at [-0.27974364  0.04052933  0.        ]
Grain 9 center of mass is located at [ 0.22478512 -0.24323939  0.        ]
Grain 10 center of mass is located at [ 0.27332932 -0.01910632  0.        ]
Grain 14 center of mass is located at [-0.19227512  0.04570894  0.        ]
Grain 16 center of mass is located at [-0.24462087  0.24956882  0.        ]
Grain 17 center of mass is located at [-0.22398418 -0.22145346  0.        ]
Grain 18 center of mass is located at [-0.26658773 -0.09434833  0.        ]
Grain 22 center of mass is located at [0.09969319 0.24543414 0.        ]
Grain 25 center of mass is located at [-0.0077  0.0259  0.    ]
Grain 32 center of mass is located at [0.2280725  0.24248306 0.        ]
Grain 37 center of mass is located at [0.29737142 0.16697936 0.        ]
Grain 40 center of mass is located at [ 0.283409   -0.16862918  0.        ]
Grain 51 center of mass is located at [-0.08731515 -0.24403782  0.        ]
Grain 52 center of mass is located at [-0.29301223  0.15198556  0.        ]
Grain 98 center of mass is located at [0.33029434 0.07187878 0.        ]

These row object can be manipulated just like Numpy structured arrays. They have the same fields as the GrainDataTable.

Grain Objects

Pymicro also has Grain objects that are specific containers equivalent to a row of the dataset GrainDataTable. You can get them with the following methods:

[7]:
# get the grain object of a specific grain
grain = micro.get_grain(18)
print(f'Grain 18 grain object:\n {grain}')
Grain 18 grain object:
 Grain
 * id = 18
 * Crystal Orientation
-------------------
orientation matrix =
 [[-0.00260576 -0.18061533 -0.9835503 ]
 [ 0.2813084   0.94370258 -0.17404314]
 [ 0.95961382 -0.2771345   0.04834955]]
Euler angles (degrees) = (  73.891,  87.229, 259.965)
Rodrigues vector = [ 0.05181912  0.97673618 -0.2321871 ]
Quaternion = (0.705, <0.037, 0.689, -0.164>)
 * center [-0.26658773 -0.09434833  0.        ]
 * has vtk mesh ? False

As you can see, a ``Grain`` object is essentially defined by its identity number and is crystal orientation. In addition, it also stores the position of the grain (center attribute).

The Grain class provides methods to get physical or crystallographic information on the grain (volume, Schmid factor, Bragg condition, orientation…). For instance, to compute the Schmid factor of the grain for a given slip system, you can proceed as follows:

[8]:
# get the lattice of the sample phase
lattice = micro.get_phase().get_lattice()

# get Schmid factor of second grain in microstructure for first basal slip system
grain_id = GrainDataTable['idnumber'][1]
grain = micro.get_grain(grain_id)
Schmid = grain.schmid_factor(lattice.get_slip_systems('basal')[0])
print(f'Schmid factor of grain {grain.id} for first basal slip system is {Schmid:1.3f}')

# get Schmid factor of grain 18 for third prismatic slip system
grain = micro.get_grain(18)
Schmid = grain.schmid_factor(lattice.get_slip_systems('prism')[2])
print(f'Schmid factor of grain {grain.id} for first basal slip system is {Schmid:1.3f}')
Schmid factor of grain 3 for first basal slip system is 0.197
Schmid factor of grain 18 for first basal slip system is 0.469

You may also get a list of grain objects that includes all grains in the dataset, with the get_all_grains method:

[9]:
# get a list of all grain objects in the microstructure
grains_list = micro.get_all_grains()
print(f'First 2 grain objects of the microstructure:\n {grains_list[:2]}')
First 2 grain objects of the microstructure:
 [Grain
 * id = 1
 * Crystal Orientation
-------------------
orientation matrix =
 [[ 0.60924219 -0.23562441 -0.75716913]
 [ 0.37332066  0.92762839  0.01171575]
 [ 0.69961106 -0.28980461  0.65311381]]
Euler angles (degrees) = (  67.499,  49.223, 270.886)
Rodrigues vector = [ 0.09452095  0.45667314 -0.19089281]
Quaternion = (0.893, <0.084, 0.408, -0.170>)
 * center [ 0.06535962 -0.13540885  0.        ]
 * has vtk mesh ? False
, Grain
 * id = 3
 * Crystal Orientation
-------------------
orientation matrix =
 [[ 0.68583138  0.57722928 -0.44321742]
 [-0.02500761  0.62734806  0.77833736]
 [ 0.7273307  -0.52272439  0.44469011]]
Euler angles (degrees) = (  54.296,  63.596, 330.341)
Rodrigues vector = [0.47176333 0.42443926 0.21837032]
Quaternion = (0.830, <0.392, 0.352, 0.181>)
 * center [-0.08418886  0.1768474   0.        ]
 * has vtk mesh ? False
]

Set GrainDataTable values

To conclude this tutorial, we will see how to add data into the GrainDataTable of a dataset. First, a new microstructure must be created to serve as an example:

[10]:
# create an empty Microstructure object
micro2 = Microstructure(filename='micro_test', autodelete=True, overwrite_hdf5=True)
# print content of grain data table
print(f'Current grain data table {micro2.grains}')
0 phases found in the data set
new phase added: unknown
Current grain data table /GrainData/GrainDataTable (Table(0,)) ''

Add grains to the Grain Data Table

New grains can be added to the GrainDataTable, it can be initialized from a list of grain orientations, with the add_grains method. To illustrate that, we will initialize the table of the new microstructure from the orientations of the example dataset:

[11]:
# get example dataset orientations
orientations = micro.grains[:]['orientation']

# count number of grains in the table
print(f'The microstructure has {micro2.get_number_of_grains()} grains')

# add new grains to new microstructure
# orientations in GrainDataTable are stored with Rodrigues vector
micro2.add_grains(orientation_list=orientations, orientation_type='rod')

# print content of grain data table
print(f'Current grain data table content (first 5 grains) \n {micro2.grains[:5]}')
print(f'Current grain ids (first 10 grains) \n {micro2.grains[:10]["idnumber"]}')

# count number of grains in the table
print(f'The microstructure has {micro2.get_number_of_grains()} grains')
The microstructure has 0 grains
adding 21 grains to the microstructure
Current grain data table content (first 5 grains)
 [([[0, 0], [0, 0], [0, 0]], [0., 0., 0.], 0, [ 0.09452096,  0.45667315, -0.1908928 ], 1, 0.)
 ([[0, 0], [0, 0], [0, 0]], [0., 0., 0.], 1, [ 0.47176334,  0.42443925,  0.21837033], 1, 0.)
 ([[0, 0], [0, 0], [0, 0]], [0., 0., 0.], 2, [ 0.7891136 , -0.56843024,  0.01993851], 1, 0.)
 ([[0, 0], [0, 0], [0, 0]], [0., 0., 0.], 3, [ 0.5407849 , -0.5829121 , -0.15143125], 1, 0.)
 ([[0, 0], [0, 0], [0, 0]], [0., 0., 0.], 4, [-0.4113469 ,  0.18637992, -0.0899675 ], 1, 0.)]
Current grain ids (first 10 grains)
 [0 1 2 3 4 5 6 7 8 9]
The microstructure has 21 grains

As you can see 21 new grains have been created from the crystal orientation provided to the add_grains method. Their idnumber has been initialized from 0 to the n umber of added grains, and all other values (centers, volumes, bounding boxes) have been initialized to zero. If we repeat the operation, we will add again 21 grains to the microstructure, with the same orientations:

[12]:
# count number of grains in the table
print(f'The microstructure has {micro2.get_number_of_grains()} grains')

# add new grains to new microstructure
# orientations in GrainDataTable are stored with Rodrigues vector
micro2.add_grains(orientation_list=orientations, orientation_type='rod')

# count number of grains in the table
print(f'The microstructure has now {micro2.get_number_of_grains()} grains')
The microstructure has 21 grains
adding 21 grains to the microstructure
The microstructure has now 42 grains

Set values from arrays

The methods to get values from the table, such as get_grain_centers, that have been shown above , have a counterpart to set these values, such as the set_grain_centers:

  • set_centers

  • set_bounding_boxes

  • set_volumes

These methods allow to set all the values of a GrainDataTable column. Hence their input must have the appropriate shape:

[13]:
# set grain centers of new microstructure from centers of example dataset
centers = micro.get_grain_centers()

# new microstructure has new 42 grains
# set new microstructure centers : 42 values must be passed
micro2.set_centers(np.concatenate((centers, centers)))

# set grain centers of new microstructure from centers of example dataset
volumes = micro.get_grain_volumes()

# new microstructure has new 42 grains
# set new microstructure centers : 42 values must be passed
micro2.set_volumes(np.concatenate((volumes, volumes)))

# set grain centers of new microstructure from centers of example dataset
bbox = micro.get_grain_bounding_boxes()

# new microstructure has new 42 grains
# set new microstructure centers : 42 values must be passed
micro2.set_bounding_boxes(np.concatenate((bbox, bbox)))
[14]:
# print content of grain data table
print(f'Current grain data table \n {micro2.grains[:]}')
Current grain data table
 [([[257, 498], [131, 334], [  0,   1]], [ 0.06535962, -0.13540885,  0.        ],  0, [ 0.09452096,  0.45667315, -0.1908928 ], 1, 9.7096439e-05)
 ([[131, 382], [361, 537], [  0,   1]], [-0.08418886,  0.1768474 ,  0.        ],  1, [ 0.47176334,  0.42443925,  0.21837033], 1, 7.6571319e-05)
 ([[169, 321], [171, 375], [  0,   1]], [-0.12312692, -0.07267088,  0.        ],  2, [ 0.7891136 , -0.56843024,  0.01993851], 1, 4.3942415e-05)
 ([[328, 523], [311, 469], [  0,   1]], [ 0.14214575,  0.08379043,  0.        ],  3, [ 0.5407849 , -0.5829121 , -0.15143125], 1, 5.3993688e-05)
 ([[105, 156], [301, 420], [  0,   1]], [-0.27974364,  0.04052933,  0.        ],  4, [-0.4113469 ,  0.18637992, -0.0899675 ], 1, 1.0572632e-05)
 ([[415, 566], [131, 189], [  0,   1]], [ 0.22478512, -0.24323939,  0.        ],  5, [-0.22051871, -0.568544  , -0.26730168], 1, 1.4035560e-05)
 ([[467, 569], [245, 391], [  0,   1]], [ 0.27332932, -0.01910632,  0.        ],  6, [ 0.7321588 ,  0.4550985 , -0.1540665 ], 1, 2.9939783e-05)
 ([[142, 249], [291, 415], [  0,   1]], [-0.19227512,  0.04570894,  0.        ],  7, [-0.8053556 ,  0.5361014 ,  0.011616  ], 1, 2.5060952e-05)
 ([[109, 212], [458, 539], [  0,   1]], [-0.24462087,  0.24956882,  0.        ],  8, [-0.79714507, -0.36815822, -0.23475127], 1, 1.3780368e-05)
 ([[106, 237], [132, 214], [  0,   1]], [-0.22398418, -0.22145346,  0.        ],  9, [ 0.0384308 , -0.5491175 ,  0.08449803], 1, 2.2212680e-05)
 ([[104, 172], [211, 312], [  0,   1]], [-0.26658773, -0.09434833,  0.        ], 10, [ 0.05181912,  0.9767362 , -0.23218708], 1, 1.5297799e-05)
 ([[335, 448], [454, 540], [  0,   1]], [ 0.09969319,  0.24543414,  0.        ], 11, [-0.18012922,  0.6727327 ,  0.25471398], 1, 1.7715263e-05)
 ([[320, 323], [343, 348], [  0,   1]], [-0.0077    ,  0.0259    ,  0.        ], 12, [ 0.15638582,  0.884963  , -0.22157212], 1, 5.4879998e-09)
 ([[441, 553], [447, 539], [  0,   1]], [ 0.2280725 ,  0.24248306,  0.        ], 13, [ 0.5988454 , -0.38010532, -0.08003835], 1, 1.8077471e-05)
 ([[499, 574], [388, 516], [  0,   1]], [ 0.29737142,  0.16697936,  0.        ], 14, [-0.7061676 ,  0.36509004,  0.0142626 ], 1, 1.5863065e-05)
 ([[484, 567], [160, 249], [  0,   1]], [ 0.283409  , -0.16862918,  0.        ], 15, [ 0.0959702 ,  0.6410337 , -0.0187812 ], 1, 1.5026144e-05)
 ([[237, 304], [133, 179], [  0,   1]], [-0.08731515, -0.24403782,  0.        ], 16, [ 0.62000704, -0.2996727 ,  0.11647069], 1, 5.2163441e-06)
 ([[106, 133], [402, 467], [  0,   1]], [-0.29301223,  0.15198556,  0.        ], 17, [ 0.5636417 , -0.5580199 , -0.15464744], 1, 3.4574400e-06)
 ([[553, 571], [358, 396], [  0,   1]], [ 0.33029434,  0.07187878,  0.        ], 18, [ 0.13639925,  0.8033593 ,  0.13590527], 1, 1.1634560e-06)
 ([[243, 266], [366, 386], [  0,   1]], [-0.1045768 ,  0.06894867,  0.        ], 19, [-0.86381924,  0.441323  , -0.05843058], 1, 7.2167200e-07)
 ([[104, 115], [194, 221], [  0,   1]], [-0.30526504, -0.1671011 ,  0.        ], 20, [-0.6494284 ,  0.26412636,  0.16653858], 1, 5.0215198e-07)
 ([[257, 498], [131, 334], [  0,   1]], [ 0.06535962, -0.13540885,  0.        ], 21, [ 0.09452096,  0.45667315, -0.1908928 ], 1, 9.7096439e-05)
 ([[131, 382], [361, 537], [  0,   1]], [-0.08418886,  0.1768474 ,  0.        ], 22, [ 0.47176334,  0.42443925,  0.21837033], 1, 7.6571319e-05)
 ([[169, 321], [171, 375], [  0,   1]], [-0.12312692, -0.07267088,  0.        ], 23, [ 0.7891136 , -0.56843024,  0.01993851], 1, 4.3942415e-05)
 ([[328, 523], [311, 469], [  0,   1]], [ 0.14214575,  0.08379043,  0.        ], 24, [ 0.5407849 , -0.5829121 , -0.15143125], 1, 5.3993688e-05)
 ([[105, 156], [301, 420], [  0,   1]], [-0.27974364,  0.04052933,  0.        ], 25, [-0.4113469 ,  0.18637992, -0.0899675 ], 1, 1.0572632e-05)
 ([[415, 566], [131, 189], [  0,   1]], [ 0.22478512, -0.24323939,  0.        ], 26, [-0.22051871, -0.568544  , -0.26730168], 1, 1.4035560e-05)
 ([[467, 569], [245, 391], [  0,   1]], [ 0.27332932, -0.01910632,  0.        ], 27, [ 0.7321588 ,  0.4550985 , -0.1540665 ], 1, 2.9939783e-05)
 ([[142, 249], [291, 415], [  0,   1]], [-0.19227512,  0.04570894,  0.        ], 28, [-0.8053556 ,  0.5361014 ,  0.011616  ], 1, 2.5060952e-05)
 ([[109, 212], [458, 539], [  0,   1]], [-0.24462087,  0.24956882,  0.        ], 29, [-0.79714507, -0.36815822, -0.23475127], 1, 1.3780368e-05)
 ([[106, 237], [132, 214], [  0,   1]], [-0.22398418, -0.22145346,  0.        ], 30, [ 0.0384308 , -0.5491175 ,  0.08449803], 1, 2.2212680e-05)
 ([[104, 172], [211, 312], [  0,   1]], [-0.26658773, -0.09434833,  0.        ], 31, [ 0.05181912,  0.9767362 , -0.23218708], 1, 1.5297799e-05)
 ([[335, 448], [454, 540], [  0,   1]], [ 0.09969319,  0.24543414,  0.        ], 32, [-0.18012922,  0.6727327 ,  0.25471398], 1, 1.7715263e-05)
 ([[320, 323], [343, 348], [  0,   1]], [-0.0077    ,  0.0259    ,  0.        ], 33, [ 0.15638582,  0.884963  , -0.22157212], 1, 5.4879998e-09)
 ([[441, 553], [447, 539], [  0,   1]], [ 0.2280725 ,  0.24248306,  0.        ], 34, [ 0.5988454 , -0.38010532, -0.08003835], 1, 1.8077471e-05)
 ([[499, 574], [388, 516], [  0,   1]], [ 0.29737142,  0.16697936,  0.        ], 35, [-0.7061676 ,  0.36509004,  0.0142626 ], 1, 1.5863065e-05)
 ([[484, 567], [160, 249], [  0,   1]], [ 0.283409  , -0.16862918,  0.        ], 36, [ 0.0959702 ,  0.6410337 , -0.0187812 ], 1, 1.5026144e-05)
 ([[237, 304], [133, 179], [  0,   1]], [-0.08731515, -0.24403782,  0.        ], 37, [ 0.62000704, -0.2996727 ,  0.11647069], 1, 5.2163441e-06)
 ([[106, 133], [402, 467], [  0,   1]], [-0.29301223,  0.15198556,  0.        ], 38, [ 0.5636417 , -0.5580199 , -0.15464744], 1, 3.4574400e-06)
 ([[553, 571], [358, 396], [  0,   1]], [ 0.33029434,  0.07187878,  0.        ], 39, [ 0.13639925,  0.8033593 ,  0.13590527], 1, 1.1634560e-06)
 ([[243, 266], [366, 386], [  0,   1]], [-0.1045768 ,  0.06894867,  0.        ], 40, [-0.86381924,  0.441323  , -0.05843058], 1, 7.2167200e-07)
 ([[104, 115], [194, 221], [  0,   1]], [-0.30526504, -0.1671011 ,  0.        ], 41, [-0.6494284 ,  0.26412636,  0.16653858], 1, 5.0215198e-07)]

The GrainDataTable has been now completely filled, and can be used to compute statistics or for various grain related data processings.

Setting data for a specific grain

To change the data stored for a specific grain, you must iterate the table to find your grain object and set one of its values as if it was a Numpy structured array. Then you have to use the specific update method on the grain row to set the value in the dataset, as follows:

[15]:
# get old orientation value
grain_orientation = micro2.GrainDataTable[15]['orientation']
print(f'The orientation of the grain is {micro2.GrainDataTable[15]["orientation"]}')

# iterate to find the grain and set its orientation to a random value
for g in micro2.grains:
    if g['idnumber'] == 15:
        g['orientation'] = np.random.rand(3)
        g.update()
print(f'The new orientation of the grain is {micro2.GrainDataTable[15]["orientation"]}')

# Set back the original value of the orientation
for g in micro2.grains:
    if g['idnumber'] == 15:
        g['orientation'] = grain_orientation
        g.update()

print(f'The orientation of the grain is back at {micro2.GrainDataTable[15]["orientation"]}')
The orientation of the grain is [ 0.0959702  0.6410337 -0.0187812]
The new orientation of the grain is [0.13544986 0.14637718 0.9661178 ]
The orientation of the grain is back at [ 0.0959702  0.6410337 -0.0187812]
[16]:
del micro2
Microstructure Autodelete:
 Removing hdf5 file micro_test.h5

Setting grain data from the Grain Map

The GrainDataTable contains data describing the grains position and morphology. These values can be computed from the grain map (see dedicated tutorial), that contains the information of the geometry of each grain. Specific methods of the Microstucture class allow to compute those values and automatically fill the GrainDataTable with them. They are:

  • recompute_grain_centers: computes and fills the center column of the GrainDataTable from the grains geometry in grain map

  • recompute_grain_volumes: computes and fills the volume column of the GrainDataTable from the grains geometry in grain map

  • recompute_grain_bounding_boxes: computes and fills the bounding_box column of the GrainDataTable from the grains geometry in grain map

If you need to call them all, you can do it at once with the build_grain_table_from_grain_map, that will first synchronize the grain ids that are in the grain map and the GrainDataTable, and then call the 3 previous methods to fill the geometric grain data in the table. Note that the

Microstructure datasets have been designed to have the ``GrainDataTable`` and the ``grain_map`` synchronized. Try to keep consistent values in your datasets to use all Pymicro’s functionalities.

This is an alternative way to initialize the GrainDataTable than the one shown above, that starts from grain orientations. This latter method is well suited for datasets created from imaging experiments.

Here is an example of out it can be done:

[17]:
# create an empty Microstructure object
micro2 = Microstructure(filename='micro_test', autodelete=True, overwrite_hdf5=True)

# print content of grain data table
print(f'Current grain data table {micro2.grains} \n')
0 phases found in the data set
new phase added: unknown
Current grain data table /GrainData/GrainDataTable (Table(0,)) ''

[18]:
# set the grain map from example dataset
micro2.set_grain_map(micro.get_grain_map(), voxel_size=micro.get_attribute('spacing','CellData')[0])

# build the grain data table from the grain map
micro2.build_grain_table_from_grain_map()

# print new grain data table
print(micro2.GrainDataTable)

adding 21 grains to the microstructure
computing grain bounding boxes: 100%|██████████| 21/21 [00:00<00:00, 1519.70it/s]
[([[257, 498], [131, 334], [  0,   1]], [ 0.06535962, -0.13540885,  0.        ],   1, [ 6.6041130e-01,  1.4333169e+00,  3.1362705e+00], 1, 9.7096439e-05)
 ([[131, 382], [361, 537], [  0,   1]], [-0.08418886,  0.1768474 ,  0.        ],   3, [ 4.3402910e+00,  3.9414454e+00, -1.0212536e+01], 1, 7.6571319e-05)
 ([[169, 321], [171, 375], [  0,   1]], [-0.12312692, -0.07267088,  0.        ],   5, [-1.4599225e+02, -3.2706104e+02, -2.5885770e+02], 1, 4.3942415e-05)
 ([[328, 523], [311, 469], [  0,   1]], [ 0.14214575,  0.08379043,  0.        ],   6, [ 1.9023380e+01, -9.4498211e-01, -5.9050403e+00], 1, 5.3993688e-05)
 ([[105, 156], [301, 420], [  0,   1]], [-0.27974364,  0.04052933,  0.        ],   7, [-1.7181755e+00, -1.8062709e-01,  1.3034259e+00], 1, 1.0572632e-05)
 ([[415, 566], [131, 189], [  0,   1]], [ 0.22478512, -0.24323939,  0.        ],   9, [ 2.6518625e-01, -1.4311209e+00,  1.3363603e+00], 1, 1.4035560e-05)
 ([[467, 569], [245, 391], [  0,   1]], [ 0.27332932, -0.01910632,  0.        ],  10, [-8.9091187e+00, -4.7538142e+00, -3.9727046e+00], 1, 2.9939783e-05)
 ([[142, 249], [291, 415], [  0,   1]], [-0.19227512,  0.04570894,  0.        ],  14, [-3.8270995e-01, -1.0366608e-01, -1.4631712e+00], 1, 2.5060952e-05)
 ([[109, 212], [458, 539], [  0,   1]], [-0.24462087,  0.24956882,  0.        ],  16, [-1.8320507e+00,  3.1252718e+00,  3.0725906e+00], 1, 1.3780368e-05)
 ([[106, 237], [132, 214], [  0,   1]], [-0.22398418, -0.22145346,  0.        ],  17, [-1.3901591e+00,  1.0782849e+00,  7.2680974e-01], 1, 2.2212680e-05)
 ([[104, 172], [211, 312], [  0,   1]], [-0.26658773, -0.09434833,  0.        ],  18, [-4.1575437e+00,  1.8096710e+00,  3.1522028e+00], 1, 1.5297799e-05)
 ([[335, 448], [454, 540], [  0,   1]], [ 0.09969319,  0.24543414,  0.        ],  22, [ 4.3339047e+00, -6.1509948e+00,  5.7741208e+00], 1, 1.7715263e-05)
 ([[320, 323], [343, 348], [  0,   1]], [-0.0077    ,  0.0259    ,  0.        ],  25, [ 4.7290218e+01, -2.7226226e+00,  1.7738430e+01], 1, 5.4879998e-09)
 ([[441, 553], [447, 539], [  0,   1]], [ 0.2280725 ,  0.24248306,  0.        ],  32, [-1.0923681e+01, -3.4582439e+01, -1.6381828e+01], 1, 1.8077471e-05)
 ([[499, 574], [388, 516], [  0,   1]], [ 0.29737142,  0.16697936,  0.        ],  37, [-1.8695880e-01,  7.7906203e-01, -2.5413555e-01], 1, 1.5863065e-05)
 ([[484, 567], [160, 249], [  0,   1]], [ 0.283409  , -0.16862918,  0.        ],  40, [ 2.1571412e+00, -1.3247006e+00,  1.7394066e-01], 1, 1.5026144e-05)
 ([[237, 304], [133, 179], [  0,   1]], [-0.08731515, -0.24403782,  0.        ],  51, [-4.4833202e+00, -1.8901974e+00, -4.6864614e+00], 1, 5.2163441e-06)
 ([[106, 133], [402, 467], [  0,   1]], [-0.29301223,  0.15198556,  0.        ],  52, [-3.4368498e+00, -9.5643365e-01,  1.1691979e+00], 1, 3.4574400e-06)
 ([[553, 571], [358, 396], [  0,   1]], [ 0.33029434,  0.07187878,  0.        ],  98, [-1.5576775e+00, -7.6267105e-01,  3.6641669e-01], 1, 1.1634560e-06)
 ([[243, 266], [366, 386], [  0,   1]], [-0.1045768 ,  0.06894867,  0.        ], 115, [-5.0699804e-02,  8.8449590e-02, -2.7226888e-02], 1, 7.2167200e-07)
 ([[104, 115], [194, 221], [  0,   1]], [-0.30526504, -0.1671011 ,  0.        ], 124, [ 5.7622421e-01,  1.3815571e+00,  2.0143840e-01], 1, 5.0215198e-07)]

The table has been created with its 'center', 'bounding_box', 'volume' columns that have been computed from the grain_map. The grain orientations have been initialized with a random value. To set user defined values, the set_orientations method can be used:

[19]:
# get orientations from example dataset
orientations = micro.get_grain_rodrigues()

# set orientations in new microstructure
micro2.set_orientations(orientations)

# print content of grain data table
print(micro2.GrainDataTable)
[([[257, 498], [131, 334], [  0,   1]], [ 0.06535962, -0.13540885,  0.        ],   1, [ 0.09452096,  0.45667315, -0.1908928 ], 1, 9.7096439e-05)
 ([[131, 382], [361, 537], [  0,   1]], [-0.08418886,  0.1768474 ,  0.        ],   3, [ 0.47176334,  0.42443925,  0.21837033], 1, 7.6571319e-05)
 ([[169, 321], [171, 375], [  0,   1]], [-0.12312692, -0.07267088,  0.        ],   5, [ 0.7891136 , -0.56843024,  0.01993851], 1, 4.3942415e-05)
 ([[328, 523], [311, 469], [  0,   1]], [ 0.14214575,  0.08379043,  0.        ],   6, [ 0.5407849 , -0.5829121 , -0.15143125], 1, 5.3993688e-05)
 ([[105, 156], [301, 420], [  0,   1]], [-0.27974364,  0.04052933,  0.        ],   7, [-0.4113469 ,  0.18637992, -0.0899675 ], 1, 1.0572632e-05)
 ([[415, 566], [131, 189], [  0,   1]], [ 0.22478512, -0.24323939,  0.        ],   9, [-0.22051871, -0.568544  , -0.26730168], 1, 1.4035560e-05)
 ([[467, 569], [245, 391], [  0,   1]], [ 0.27332932, -0.01910632,  0.        ],  10, [ 0.7321588 ,  0.4550985 , -0.1540665 ], 1, 2.9939783e-05)
 ([[142, 249], [291, 415], [  0,   1]], [-0.19227512,  0.04570894,  0.        ],  14, [-0.8053556 ,  0.5361014 ,  0.011616  ], 1, 2.5060952e-05)
 ([[109, 212], [458, 539], [  0,   1]], [-0.24462087,  0.24956882,  0.        ],  16, [-0.79714507, -0.36815822, -0.23475127], 1, 1.3780368e-05)
 ([[106, 237], [132, 214], [  0,   1]], [-0.22398418, -0.22145346,  0.        ],  17, [ 0.0384308 , -0.5491175 ,  0.08449803], 1, 2.2212680e-05)
 ([[104, 172], [211, 312], [  0,   1]], [-0.26658773, -0.09434833,  0.        ],  18, [ 0.05181912,  0.9767362 , -0.23218708], 1, 1.5297799e-05)
 ([[335, 448], [454, 540], [  0,   1]], [ 0.09969319,  0.24543414,  0.        ],  22, [-0.18012922,  0.6727327 ,  0.25471398], 1, 1.7715263e-05)
 ([[320, 323], [343, 348], [  0,   1]], [-0.0077    ,  0.0259    ,  0.        ],  25, [ 0.15638582,  0.884963  , -0.22157212], 1, 5.4879998e-09)
 ([[441, 553], [447, 539], [  0,   1]], [ 0.2280725 ,  0.24248306,  0.        ],  32, [ 0.5988454 , -0.38010532, -0.08003835], 1, 1.8077471e-05)
 ([[499, 574], [388, 516], [  0,   1]], [ 0.29737142,  0.16697936,  0.        ],  37, [-0.7061676 ,  0.36509004,  0.0142626 ], 1, 1.5863065e-05)
 ([[484, 567], [160, 249], [  0,   1]], [ 0.283409  , -0.16862918,  0.        ],  40, [ 0.0959702 ,  0.6410337 , -0.0187812 ], 1, 1.5026144e-05)
 ([[237, 304], [133, 179], [  0,   1]], [-0.08731515, -0.24403782,  0.        ],  51, [ 0.62000704, -0.2996727 ,  0.11647069], 1, 5.2163441e-06)
 ([[106, 133], [402, 467], [  0,   1]], [-0.29301223,  0.15198556,  0.        ],  52, [ 0.5636417 , -0.5580199 , -0.15464744], 1, 3.4574400e-06)
 ([[553, 571], [358, 396], [  0,   1]], [ 0.33029434,  0.07187878,  0.        ],  98, [ 0.13639925,  0.8033593 ,  0.13590527], 1, 1.1634560e-06)
 ([[243, 266], [366, 386], [  0,   1]], [-0.1045768 ,  0.06894867,  0.        ], 115, [-0.86381924,  0.441323  , -0.05843058], 1, 7.2167200e-07)
 ([[104, 115], [194, 221], [  0,   1]], [-0.30526504, -0.1671011 ,  0.        ], 124, [-0.6494284 ,  0.26412636,  0.16653858], 1, 5.0215198e-07)]

This concludes the tutorial on Pymicro’s grain data !

[20]:
del micro2
del micro
Microstructure Autodelete:
 Removing hdf5 file micro_test.h5