Skip to content

Instantly share code, notes, and snippets.

@Bismarrck
Last active June 4, 2019 05:18
Show Gist options
  • Save Bismarrck/a68da01f19b39320f78a to your computer and use it in GitHub Desktop.
Save Bismarrck/a68da01f19b39320f78a to your computer and use it in GitHub Desktop.
Conversion between fractional and cartesian coordinates.
import numpy as np
def get_fractional_to_cartesian_matrix(a, b, c, alpha, beta, gamma,
angle_in_degrees=True):
"""
Return the transformation matrix that converts fractional coordinates to
cartesian coordinates.
Parameters
----------
a, b, c : float
The lengths of the edges.
alpha, gamma, beta : float
The angles between the sides.
angle_in_degrees : bool
True if alpha, beta and gamma are expressed in degrees.
Returns
-------
r : array_like
The 3x3 rotation matrix. ``V_cart = np.dot(r, V_frac)``.
"""
if angle_in_degrees:
alpha = np.deg2rad(alpha)
beta = np.deg2rad(beta)
gamma = np.deg2rad(gamma)
cosa = np.cos(alpha)
sina = np.sin(alpha)
cosb = np.cos(beta)
sinb = np.sin(beta)
cosg = np.cos(gamma)
sing = np.sin(gamma)
volume = 1.0 - cosa**2.0 - cosb**2.0 - cosg**2.0 + 2.0 * cosa * cosb * cosg
volume = np.sqrt(volume)
r = np.zeros((3, 3))
r[0, 0] = a
r[0, 1] = b * cosg
r[0, 2] = c * cosb
r[1, 1] = b * sing
r[1, 2] = c * (cosa - cosb * cosg) / sing
r[2, 2] = c * volume / sing
return r
def get_cartesian_to_fractional_matrix(a, b, c, alpha, beta, gamma,
angle_in_degrees=True):
"""
Return the transformation matrix that converts cartesian coordinates to
fractional coordinates.
Parameters
----------
a, b, c : float
The lengths of the edges.
alpha, gamma, beta : float
The angles between the sides.
angle_in_degrees : bool
True if alpha, beta and gamma are expressed in degrees.
Returns
-------
r : array_like
The 3x3 rotation matrix. ``V_frac = np.dot(r, V_cart)``.
"""
if angle_in_degrees:
alpha = np.deg2rad(alpha)
beta = np.deg2rad(beta)
gamma = np.deg2rad(gamma)
cosa = np.cos(alpha)
sina = np.sin(alpha)
cosb = np.cos(beta)
sinb = np.sin(beta)
cosg = np.cos(gamma)
sing = np.sin(gamma)
volume = 1.0 - cosa**2.0 - cosb**2.0 - cosg**2.0 + 2.0 * cosa * cosb * cosg
volume = np.sqrt(volume)
r = np.zeros((3, 3))
r[0, 0] = 1.0 / a
r[0, 1] = -cosg / (a * sing)
r[0, 2] = (cosa * cosg - cosb) / (a * volume * sing)
r[1, 1] = 1.0 / (b * sing)
r[1, 2] = (cosb * cosg - cosa) / (b * volume * sing)
r[2, 2] = sing / (c * volume)
return r
@DavidCdeB
Copy link

Well done ;) This is awesome.
However, I have experienced the following issue:

Say I have a trigonal cell, and I am using the 2nd function to convert Cartesian to fractional:
The Cartesian coordinates of the atom No. 3 I am looking at are:

cart_atom_3 = np.array ([[ -2.917610977644E+00, 0.000000000000E+00, -1.436158568333E+00 ]])

Now, the fractional coordinates shall be given by frac_atom_3 as:

r = get_cartesian_to_fractional_matrix(6.44307976, 6.44307976, 6.44307976, 46.178072, 46.178072, 46.178072)
frac_atom_3 = np.dot(r, np.transpose(cart_atom_3))
print  'frac_atom_3 = ', frac_atom_3

The result is the following:

frac_atom_3 =  [[-0.3143078 ]
 [ 0.13852083]
 [-0.33857421]]

However, the fractional coordinates printed for this atom No. 3 in the main code for simulation I am using are:

2.500000000000E-01 2.500000000000E-01 2.500000000000E-01

  1. Do you know what might be happening?
  2. Where did you get these mathematical expressions from?
    It would be great if you could include the source to keep the algorithm consistent with the math derivation.
  3. Could you check this 2nd function for converting cart -> frac in a trigonal case ? - Do you reproduce the same issue?

Again, thank you for the effort, this code is awesome
Contact me if you need: davidcarrascobustur@gmail.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment