Skip to content

Inverse Pole Figures

Inverse pole figures (IPFs) are used in materials science and crystallography to analyze the orientation of crystal grains relative to a specific direction in a material, such as the rolling or normal direction. Unlike traditional pole figures, which map crystallographic directions to a specimen's reference frame, IPFs show how a particular sample direction aligns with the crystallographic axes within individual grains. This information helps in understanding the material's texture, which influences properties such as strength, ductility, and anisotropy.

In this tutorial, we will work with data from the T11_02_ReXRandom example, which simulates the grain recrystallization process of a single-phase anisotropic and cubic material. The microstructure is randomly generated and consists of 30 grains of 4 different types, each representing different energy ranges. By analyzing this simulated microstructure, we will learn how to visualize grain orientations using IPFs and gain insights into the texture development during recrystallization.

We will combine grain structure data from a MICRESS .korn binary file with phase and orientation information from a .TabO tabular file. After processing this data, we will generate IPFs for the grains and display them using Orix, a Python library for crystallographic analysis.

Step 1: Extract Grain Structure Data

First, we need to extract the spatial arrangement of grains from the .korn binary file. Here, we load the grain structure data from the last time step of the MICRESS simulation.

1
2
3
4
5
from micpy import bin

# Load the grain structure data from the last time step
with bin.File("T11_02_ReXRandom.korn") as f:
    grains = f.read_field(-1)

Step 2: Load Orientation and Phase Data

Next, we load the phase and orientation data from the .TabO tabular file corresponding to the same simulation time as the grain data.

from micpy import tab

# Load the orientation and phase data from the tabular file
df = tab.read("T11_02_ReXRandom.TabO")

# Filter the data to match the time step of the grain data
df = df.loc[df["Simulation time [s]"] == grains.time]

This gives us a DataFrame containing information about each grain's phase and orientation (as quaternions) at the current time step.

Step 3: Map Grain Data to Orientation and Phase

We now map the grain numbers to their respective phases and orientations, combining the data from the .korn and .TabO files.

# Extract the phase numbers and quaternion orientation data
phases = df["Ph. Nb."].values
orientations = df[
    ["Quaternion_0 [-]", "Quaternion_1 [-]", "Quaternion_2 [-]", "Quaternion_3 [-]"]
].values

# Create a dictionary mapping grain numbers to their phases and orientations
grain_map = dict(zip(df["Gr. Nb."], zip(phases, orientations)))

# For each grain in the 3D array, extract its corresponding phase and orientation
phases, orientations  = zip(*[grain_map[grain] for grain in grains.flatten()])

Step 4: Create a Crystal Map

Now, we create a crystal map containing the grain phases and orientations. This map will be used for visualizing the inverse pole figures.

import numpy as np
from orix.crystal_map import CrystalMap, PhaseList, Phase
from orix.quaternion import Orientation

# Convert the quaternion data into orientation objects
rotations = Orientation(orientations)

# Define the spatial dimensions
dimx, dimy, dimz = grains.shape
x = np.tile(np.arange(dimz), dimx)
y = np.repeat(np.arange(dimx), dimz)

# Define phases in the material
phase_list = PhaseList([Phase(name="FCC", point_group="m-3m")])

# Create the crystal map using the orientations and phases
crystal_map = CrystalMap(
    rotations=rotations, phase_id=phases, x=x, y=y, phase_list=phase_list
)

The CrystalMap object now holds the orientation and phase information, ready for plotting.

Step 5: Generate IPF Colors

Using Orix, we can map the grain orientations to colors based on the crystal symmetry (e.g., FCC structure). Here, we generate RGB colors for the grain orientations.

from orix import plot
from orix.vector import Vector3d

# Define an IPF color key for the FCC phase along the z-axis
color_key = plot.IPFColorKeyTSL(
    crystal_map.phases["FCC"].point_group, direction=Vector3d.zvector()
)

# Generate RGB colors for the grain orientations of the FCC phase
colors_fcc = color_key.orientation2color(crystal_map["FCC"].orientations)

# Create a full RGB array, where colors are applied only to FCC grains
colors_all = np.zeros((crystal_map.size, 3))
colors_all[crystal_map.phase_id == 1] = colors_fcc

Step 6: Visualize the Grain Orientations

Now that we have the colors for the grains, we can plot the crystal map to visualize the grain orientations. Each color in the plot corresponds to a specific crystallographic direction.

# Plot the crystal map with the generated RGB colors
fig = crystal_map.plot(colors_all, return_figure=True, scalebar=False)

# Customize the plot
fig.set_size_inches(6, 4)
ax = fig.axes[0]
ax.set_title("Grain Orientations")
ax.set_xlabel("x")
ax.set_ylabel("z")
ax.invert_yaxis()
ax.set_frame_on(False)

Step 7: Add a Color Key to the Plot

To make the plot more informative, we add a color key that shows the crystallographic direction associated with each color.

# Add a legend to indicate the IPF key
ax_legend = fig.add_axes(
    [0.7, 0.5, 0.2, 0.2],
    projection="ipf",
    symmetry=crystal_map.phases["FCC"].point_group,
)
ax_legend.plot_ipf_color_key()

# Customize legend appearance
ax_legend.set_title("FCC")
for text in ax_legend.texts:
    text.set_fontsize(10)
for patch in ax_legend.patches:
    patch.set_visible(False)

The result is a plot where grain orientations are represented by colors according to the inverse pole figure (IPF). Each grain's orientation is mapped to a crystallographic direction, and the color key explains how the colors correspond to specific directions within the crystal structure.

Step 8: Generate Pole Density Plots

In addition to IPFs, we can create pole density plots to visualize the distribution of crystallographic directions within the grains. Here, we generate pole density plots for the FCC phase along the z-axis.

# Specify the viewing direction for the pole density plot
direction = Vector3d.zvector()

# Create a figure and axis for the pole density plot
fig, ax = plt.subplots(figsize=(4, 4), subplot_kw={
    "projection": "ipf",
    "symmetry": crystal_map.phases["FCC"].point_group,
    "direction": direction,
})

# Plot the pole density function for the FCC phase
orie_fcc = crystal_map["FCC"].orientations * direction
ax.pole_density_function(orie_fcc, vmin=0, vmax=3)

# Customize the plot
ax.set_title("FCC Pole Density\nZ-Direction")
for text in ax.texts:
    text.set_fontsize(10)

The pole density plot shows the distribution of crystallographic directions within the FCC phase along the z-axis. The color intensity indicates the density of orientations in each direction, providing insights into the texture development of the material.