Problem with angle calculation

Hi,
I want to calculate angles between sites 1, 2 and 3, so I write the following:

angle=struct.get_angle(site1,site2,site3)

In site1, site2 and site3 I have to write integrers which are the number of each atom.
Is there any method to write xyz coordinates intead of integrers?

My problem comes because I have an atom A in the (0.9,0.9,0.9) position and I want to calculate the angle with its nearest atoms. So the program, instead of taking the (1.1,1.1,1.1) position of atom B (which is the closest distance), it takes the (0.1,0.1,0.1) position (which is farther), so the angle is different (of course, there is a third atom in the equation but for simplifying I just wrote 2).

So I think that if I write the xyz coordinates of the site, instead of the atom number, this problem could be solved. However, I cannot do it :frowning:

Thanks
Jon

Hi Jon,

If you have the coordinates you can do this using:

from pymatgen.util.coord import get_angle

v1 = site1_coords - site2_coords
v2 = site3_coords - site2_coords

angle = get_angle(v1, v2, units="degrees")

Note your coordinates should be in cartesian coordinates. If you want to convert fractional to cartesian coordinates you can use:

cart_coords = struct.lattice.get_cartesian_coords(frac_coords)

Best,
Alex

1 Like

Hi Alex,
Thanks for your fast response.
Indeed, what I have is the preriodic site:

in: struct[2]
out: PeriodicSite: O2- (-0.1056, 2.1684, 8.1454) [-0.0128, 0.2628, 0.9872]

I am not able to take from here the (-0.1056, 2.1684, 8.1454) coordinates. How can I get the coordinates from here?

You can get the cartesian or fractional coordinates of a site in a structure object using:

cart_coords = struct[2].coords
frac_coords = struct[2].frac_coords

However, this will not help your original scenario as this will still be the coordinates of the original site and not the coordinates of the site in the closest image.

I’ve made a function that works like the original struct.get_angle but this time it will find the angle between the sites in the closest periodic image.

from pymatgen import Structure
from pymatgen.util.coord import pbc_diff, get_angle

def get_angle_between_closest_sites(
    structure: Structure, 
    i: int, 
    j: int, 
    k: int
) -> float:
    """
    Returns angle specified by three sites where the closest image
    of the sites i and k to the central site, j, is used.

    Args:
        structure: A structure object.
        i: Index of first site.
        j: Index of second site.
        k: Index of third site.

    Returns:
        Angle in degrees.
    """
    v1 = pbc_diff(structure[i].frac_coords, structure[j].frac_coords)
    v2 = pbc_diff(structure[k].frac_coords, structure[j].frac_coords)
    
    cart_v1 = structure.lattice.get_cartesian_coords(v1)
    cart_v2 = structure.lattice.get_cartesian_coords(v2)

    return get_angle(cart_v1, cart_v2, units="degrees")


get_angle_between_closest_sites(structure, 0, 1, 2)

Thank you very much Alex, this worked perfectly for me.