Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/cmelab/cmeutils into movi…
Browse files Browse the repository at this point in the history
…e-maker
  • Loading branch information
chrisjonesBSU committed Dec 19, 2023
2 parents f85cff8 + 6fa75c4 commit beae55b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ repos:
- id: trailing-whitespace
exclude: 'cmeuitls/tests/assets/.*'
- repo: https://github.com/psf/black
rev: 23.11.0
rev: 23.12.0
hooks:
- id: black
args: [--line-length=80]
- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort
name: isort (python)
Expand Down
2 changes: 1 addition & 1 deletion cmeutils/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.3"
__version__ = "1.1.1"
27 changes: 27 additions & 0 deletions cmeutils/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@
from numpy.linalg import svd


def get_backbone_vector(coordinates):
"""Calculates the line of bets fit through a set of 3D coordinates.
Best fit is calculated using numpy's Singular Value Decomposition.
Parameters
----------
coordinates : numpy.ndarray, shape (N,3)
Coordinates (x,y,z) through which to fit a plane. Must be at least 3
points.
Returns
-------
direction_vector : numpy.ndarray, shape (3,)
The vector of the best fit line.
"""
if coordinates.shape[0] < 2:
raise ValueError("Coordinates must contain at least 2 points.")
# Center the coordinates (subtract the mean)
centered_coordinates = coordinates - np.mean(coordinates, axis=0)
# Use PCA to find the principal components
_, _, V = np.linalg.svd(centered_coordinates)
# The first principal component (V[0]) is the vec of the best-fit line
direction_vector = V[0]
return direction_vector


def get_plane_normal(points):
"""Calculate the plane which best fits a cloud of points.
Expand Down
20 changes: 20 additions & 0 deletions cmeutils/tests/test_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import numpy as np
import pytest
from base_test import BaseTest
from mbuild.lib.recipes import Alkane

from cmeutils.geometry import (
angle_between_vectors,
get_backbone_vector,
get_plane_normal,
moit,
radial_grid_positions,
Expand All @@ -14,6 +16,24 @@


class TestGeometry(BaseTest):
def test_backbone_vector(self):
z_coords = np.array([[0, 0, 1], [0, 0, 2], [0, 0, 3]])
backbone = get_backbone_vector(z_coords)
assert np.allclose(np.abs(backbone), np.array([0, 0, 1]), atol=1e-5)

x_coords = np.array([[1, 0, 0], [2, 0, 0], [3, 0, 0]])
backbone = get_backbone_vector(x_coords)
assert np.allclose(np.abs(backbone), np.array([1, 0, 0]), atol=1e-5)

mb_chain = Alkane(n=20)
backbone = get_backbone_vector(mb_chain.xyz)
assert np.allclose(np.abs(backbone), np.array([0, 1, 0]), atol=1e-2)

def test_backbone_vector_bad_input(self):
with pytest.raises(ValueError):
coordinates = np.array([1, 1, 1])
get_backbone_vector(coordinates)

def test_moit(self):
_moit = moit(points=[(-1, 0, 0), (1, 0, 0)], masses=[1, 1])
assert np.array_equal(_moit, np.array([0, 2.0, 2.0]))
Expand Down

0 comments on commit beae55b

Please sign in to comment.