Calculating structural properties
Quite often you want to calculate some geometric, structural properties of a
structure or set of structures, for example the mean bond angles between certain
species, or the polyhedral strain. This tutorial goes through various ways to
easily extract such quantities from .magres
files.
As usual, we start by importing the MagresAtoms
Python class and reading in a
.magres
file to the atoms
variable.
from magres.atoms import MagresAtoms
atoms = MagresAtoms.load_magres('../samples/T1Si0.magres')
Bond lengths
We can calculate the distance between two atoms, for example between the Al1 atom and its neighbour, the O1 atom.
atoms.dist(atoms.Al1, atoms.O1)
1.7623362335263948
We might then calculate the distance between Al1 and the Si1 atom bonded to the bridging O1 atom.
atoms.dist(atoms.Al1, atoms.Si1)
2.9562849997928144
Let’s loop over the first two aluminium atoms (for sake of space) and print out the Al-O bond length.
for atom_Al in atoms.species('Al')[:2]:
for atom_O in atoms.species('O').within(atom_Al, 3.0):
print atom_Al, atom_O, atoms.dist(atom_Al, atom_O)
27Al1 17O1 1.76233623353 27Al1 17O18 1.75419940144 27Al1 17O31 1.76324628229 27Al1 17O44 1.75655859851 27Al2 17O5 1.75237010931 27Al2 17O6 1.72876661236 27Al2 17O7 1.77878020002 27Al2 17O8 1.76119987509
We could take a mean to find out the average Al-O bond length, with a standard deviation.
dists = []
for atom_Al in atoms.species('Al'):
for atom_O in atoms.species('O').within(atom_Al, 3.0):
dists.append(atoms.dist(atom_Al, atom_O))
print "Mean bond length =", mean(dists), "+-", std(dists)
Mean bond length = 1.75230470421 +- 0.0209888992786
And we could even plot a histogram of the Al-O bond length distribution.
hist(dists, bins=20)
(array([ 4., 2., 4., 10., 12., 12., 20., 16., 11., 15., 12., 23., 12., 14., 11., 3., 3., 2., 3., 3.]), array([ 1.70591764, 1.71088507, 1.7158525 , 1.72081992, 1.72578735, 1.73075478, 1.7357222 , 1.74068963, 1.74565706, 1.75062449, 1.75559191, 1.76055934, 1.76552677, 1.7704942 , 1.77546162, 1.78042905, 1.78539648, 1.7903639 , 1.79533133, 1.80029876, 1.80526619]), <a list of 20 Patch objects>)
Bond angles
We can use the angle function to calculate the X-Y-Z bond angle of three atoms, X, Y and Z. For example, the Al1-O1-S1 bond angle is
atoms.angle(atoms.Al1, atoms.O1, atoms.Si1)
2.1049612709736554
That’s in radians. If we want it in degrees, we can either do the maths or specify the degrees option.
atoms.angle(atoms.Al1, atoms.O1, atoms.Si1, degrees=True)
120.60539686528409
We could do a similar thing as we did with bond lengths to look at the Al-O-X bond angle distribution, where X is any second nearest neighbour.
angles = []
# Loop over every aluminium atom
for atom_Al in atoms.species('Al'):
# Find all oxygens within 2.0 A of the Al atom, i.e. ones bonded
for atom_O in atoms.species('O').within(atom_Al, 2.0):
# Find all Si and Al within 2.0 of the bonded oxygen
for atom_X in atoms.species('Si', 'Al').within(atom_O, 2.0):
# Check that we haven't found the original Al atom! Otherwise angle will equal zero
if atom_Al != atom_X:
angle = atoms.angle(atom_Al, atom_O, atom_X, degrees=True)
# Append it to our list
angles.append(angle)
print "Mean bond angle =", mean(angles), "+-", std(angles)
Mean bond angle = 119.244646177 +- 5.4306395789
Plotting this distribution as a histogram we can see that there are two populations of bond angles, corresponding to the T1 (four-coordinated) and T2 (three-coordinated) sites.
hist(angles, bins=20)
(array([ 6., 20., 22., 26., 16., 16., 8., 13., 14., 3., 0., 0., 0., 6., 4., 4., 3., 1., 4., 2.]), array([ 112.17244747, 113.33907751, 114.50570755, 115.67233759, 116.83896763, 118.00559767, 119.17222771, 120.33885775, 121.5054878 , 122.67211784, 123.83874788, 125.00537792, 126.17200796, 127.338638 , 128.50526804, 129.67189808, 130.83852812, 132.00515816, 133.1717882 , 134.33841824, 135.50504828]), <a list of 20 Patch objects>)