File size: 3,418 Bytes
ce9690f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | import os
import numpy as np
def format(fname: str) -> str:
"""
Extract format extension from file name.
Parameters
----------
fname : str
File name
Returns
-------
str
File extension
Notes
-----
The file extension is returned without the `.` character, i.e. for the file
`path/filename.ext` the string `ext` is returned.
If a file is compressed, the `.gz` extension is ignored.
"""
name, ext = os.path.splitext(fname)
if ext == ".gz":
_, ext = os.path.splitext(name)
return ext[1:] # Remove "."
def molformat(fname: str) -> str:
"""
Extract an OpenBabel-friendly format from file name.
Parameters
----------
fname : str
File name
Returns
-------
str
File extension in an OpenBabel-friendly format
Notes
-----
File types in OpenBabel do not always correspond to the file extension. This
function converts the file extension to an OpenBabel file type.
The following table shows the different conversions performed by this function:
========= =========
Extension File Type
--------- ---------
xyz XYZ
========= =========
"""
ext = format(fname)
if ext == "xyz":
# xyz files in OpenBabel are called XYZ
ext = "XYZ"
return ext
def deg_to_rad(angle: float) -> float:
"""
Convert angle in degrees to angle in radians.
Parameters
----------
angle : float
Angle (in degrees)
Returns
-------
float
Angle (in radians)
"""
return angle * np.pi / 180.0
def rotate(
v: np.ndarray, angle: float, axis: np.ndarray, units: str = "rad"
) -> np.ndarray:
"""
Rotate vector.
Parameters
----------
v: numpy.array
3D vector to be rotated
angle : float
Angle of rotation (in `units`)
axis : numpy.array
3D axis of rotation
units: {"rad", "deg"}
Units of `angle` (in radians `rad` or degrees `deg`)
Returns
-------
numpy.array
Rotated vector
Raises
------
AssertionError
If the axis of rotation is not a 3D vector
ValueError
If `units` is not `rad` or `deg`
"""
assert len(axis) == 3
# Ensure rotation axis is normalised
axis = axis / np.linalg.norm(axis)
if units.lower() == "rad":
pass
elif units.lower() == "deg":
angle = deg_to_rad(angle)
else:
raise ValueError(
f"Units {units} for angle is not supported. Use 'deg' or 'rad' instead."
)
t1 = np.outer(axis, np.inner(axis, v)).T
t2 = np.cos(angle) * np.cross(np.cross(axis, v), axis)
t3 = np.sin(angle) * np.cross(axis, v)
return t1 + t2 + t3
def center_of_geometry(coordinates: np.ndarray) -> np.ndarray:
"""
Center of geometry.
Parameters
----------
coordinates: np.ndarray
Coordinates
Returns
-------
np.ndarray
Center of geometry
"""
assert coordinates.shape[1] == 3
return np.mean(coordinates, axis=0)
def center(coordinates: np.ndarray) -> np.ndarray:
"""
Center coordinates.
Parameters
----------
coordinates: np.ndarray
Coordinates
Returns
-------
np.ndarray
Centred coordinates
"""
return coordinates - center_of_geometry(coordinates)
|