Rotational orientation analysis
In many crystalline materials, coordination polyhedra can adopt discrete orientational states with respect to the crystal lattice. Tracking which orientation each polyhedron has – and how orientations change in a molecular dynamics trajectory – gives insight into rotational dynamics and phase transitions.
Defining reference orientations
The
RotationAnalyser class
classifies polyhedra against one or more reference orientations. Each
reference orientation is defined as a set of centre-to-vertex vectors
(an Nx3 array). All reference orientations must be rotated copies of the
same geometry (they share the same point group).
For a single reference orientation, pass an Nx3 array:
import numpy as np
from polyhedral_analysis.rotation_analyser import RotationAnalyser
# A single reference orientation for a tetrahedron
reference = np.array([[ 1.0, -1.0, 1.0],
[-1.0, -1.0, -1.0],
[ 1.0, 1.0, -1.0],
[-1.0, 1.0, 1.0]])
analyser = RotationAnalyser(reference)
For multiple reference orientations (e.g. two distinct octahedral tilts in a perovskite), pass an MxNx3 array:
# Two reference orientations for an octahedron
references = np.array([
ref_orientation_1, # 6x3 array
ref_orientation_2, # 6x3 array
])
analyser = RotationAnalyser(references)
Classifying polyhedron orientations
The
polyhedron_orientation()
method takes a
CoordinationPolyhedron
and returns a dictionary describing its closest discrete orientation:
result = analyser.polyhedron_orientation(poly)
result['orientation_index'] # index of the closest orientation
result['reference_geometry_index'] # which reference geometry it matches
result['rotational_distance'] # angle from nearest orientation (radians)
result['symmetry_measure'] # CSM for this polyhedron
result['all_rotational_distances'] # distances to every orientation
The orientation_index identifies one of the M * n_G
orientations, where M is the number of reference geometries and n_G
is the order of the point group. The
reference_geometry_index maps back to the input reference array.
For working directly with vertex vector arrays (without a
CoordinationPolyhedron object), use
discrete_orientation():
points = poly.vertex_vectors(reference='central_atom')
result = analyser.discrete_orientation(points)
Orientation order parameters
The polyhedral_analysis.orientation_parameters module provides
functions for quantifying how well a polyhedron is aligned with the
Cartesian axes.
oct_rotational_order_parameter()
computes an order parameter for an octahedron’s alignment with the
<100> directions. It takes a 6x3 array of centroid-centred vertex
vectors:
from polyhedral_analysis.orientation_parameters import oct_rotational_order_parameter
points = poly.vertex_vectors(reference='centroid')
oct_rotational_order_parameter(points)
# 1.0 for a perfectly aligned octahedron
# 0.33 for a 45-degree rotated octahedron
The underlying utility functions are also available:
projection_xyz()– maximum projection score of a vector onto the Cartesian axes (1.0 when parallel to an axis, -1/3 when equally spaced between all three).cos_theta()– cosine of the angle between two vectors.
Visualising orientation distributions
The
plot_orientation_distribution()
function creates a contour map of the probability density for a set of
vertex orientations. This is useful for visualising the distribution of
orientations across a trajectory or set of configurations:
from polyhedral_analysis.plotting import plot_orientation_distribution
# Collect (theta, phi) orientations from all polyhedra in a trajectory
orientations = []
for config in trajectory.configurations:
for poly in config.polyhedra:
orientations.extend(poly.vertex_vector_orientations())
fig = plot_orientation_distribution(orientations)
The vertex orientations are obtained using
vertex_vector_orientations()
(see Geometric analysis).
Customisation options:
from cmcrameri import cm
fig = plot_orientation_distribution(
orientations,
title='Vertex orientations',
figsize=(12, 10),
cmap=cm.batlow, # any matplotlib-compatible colourmap
fontsize=14,
plot=True, # display immediately
)
Tracking orientations across a trajectory
Combining the
RotationAnalyser with a
Trajectory lets you track how
individual polyhedra reorient over the course of a simulation:
from polyhedral_analysis.polyhedron_trajectory import PolyhedronTrajectory
# Track the first polyhedron across all frames
poly_traj = PolyhedronTrajectory(
polyhedra=[config.polyhedra[0] for config in trajectory.configurations],
)
# Classify the orientation in each frame
orientation_indices = [
analyser.polyhedron_orientation(p)['orientation_index']
for p in poly_traj.polyhedra
]
See Analysing trajectories for more on working with trajectories and polyhedron trajectories.