Skip to content

Commit

Permalink
More generator stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
lucas-wilkins committed Jan 22, 2025
1 parent e6885c5 commit c975c45
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 3 deletions.
66 changes: 66 additions & 0 deletions pyspinw/util/apply_generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import numpy as np


def _remove_duplicates_and_order_points(points: np.ndarray, tol=1e-8) -> np.ndarray:
# Remove duplicates first, as order might be very sensitive to rounding
tol_squared = tol*tol

unique_points = []
for i in range(points.shape[0]):
test_point = points[i, :]
for unique_point in unique_points:
if np.sum((unique_point - test_point)**2) < tol_squared:
break
else:
unique_points.append(test_point)

output = np.array(unique_points)
output = output[output[:,0].argsort(), :] # Fastest search

for i in range(1, output.shape[1]):
output = output[output[:, i].argsort(kind='mergesort'), :] # mergesort keeps order from other dimensions

return output



def apply_generators_with_moments(points: np.ndarray, generators: list[tuple[np.ndarray, np.ndarray, float]]) -> np.ndarray:

for quadratic, linear, time_reversal in generators:

transformed_positions = points[:, :3] @ quadratic + linear
transformed_positions %= 1 # Move back to unit cell

transformed_moments = time_reversal * points[:, 3:]


joined = np.concatenate((points,
np.concatenate((transformed_positions, transformed_moments), axis=1)), axis=0)

points = _remove_duplicates_and_order_points(joined)

return points

def apply_generators_until_stable(
points: np.ndarray,
generators: list[tuple[np.ndarray, np.ndarray, float]], tol=1e-8,
max_iters: int=1000) -> np.ndarray:

points = _remove_duplicates_and_order_points(points)


for i in range(max_iters): # Big but finite number
# print(i)
new_points = apply_generators_with_moments(points, generators)

if new_points.shape != points.shape:
points = new_points
continue

difference = np.sum((points - new_points)**2)

if difference < new_points.shape[0]*new_points.shape[1]*tol*tol:
return points

raise Exception(f"Failed to reach steady state after {max_iters} iterations")

9 changes: 8 additions & 1 deletion pyspinw/util/group_generators.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy as np
import re

from safe_expression_evaluation import evaluate_algebra
from pyspinw.util.safe_expression_evaluation import evaluate_algebra

_number_regex = r"\d+(?:\.\d+)?"
_symbol_regex = r"x|y|z|\-|\+|/|\*"
Expand Down Expand Up @@ -125,6 +125,13 @@ def parse_one_line_generators(generator_string: str):

return output

def spglib_generators_to_list(generators: dict) -> list[tuple[np.ndarray, np.ndarray, float]]:
rotations = generators["rotations"]
translations = generators["translations"]
time_reversals = generators["time_reversals"]

return [(rotations[i,:,:], translations[i,:], -1.0 if time_reversals[i] < 0.5 else 1.0)
for i in range(len(time_reversals))]

if __name__ == "__main__":
from pyspinw.util.magnetic_symmetry import name_converter
Expand Down
2 changes: 0 additions & 2 deletions pyspinw/util/magnetic_symmetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from dataclasses import dataclass

from Tools.scripts.stable_abi import generators

""" Deals with magnetic symmetry group names and numbers """

@dataclass
Expand Down
52 changes: 52 additions & 0 deletions tests/test_apply_generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import pytest

import numpy as np
from pyspinw.util.apply_generators import _remove_duplicates_and_order_points

def test_order_unique_helper_removes_duplicates():
""" Test that the helper function that finds unique entries removes duplicates"""

test_data = np.array([
[1,2,3],
[3,4,5],
[2,3,4],
[2,3,4],
[1,2,3],
[1,2,3]
])

expected = np.array([
[1,2,3],
[2,3,4],
[3,4,5]
])

unique = _remove_duplicates_and_order_points(test_data)

assert unique.shape == (3, 3)

assert unique == pytest.approx(expected, abs=1e-10)

def test_order_unique_helper_gives_well_defined_order():
""" Test that ordering of points is uniquely defined """
test_data = np.array([
[1,1,1],
[1,0,1],
[1,0,1],
[0,1,1],
[0,0,0], # 5
[0,1,0],
[0,1,1],
[1,1,0],
[0,0,1],
[0,1,0] # 10
])

another_order = [3,2,7,5,9,1,0,4,8,6]

other_test_data = test_data[another_order, :]

first_way = _remove_duplicates_and_order_points(test_data)
second_way = _remove_duplicates_and_order_points(other_test_data)

assert first_way == pytest.approx(second_way, abs=1e-10)
17 changes: 17 additions & 0 deletions tests/test_spglib_access.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
import pytest
import spglib

from pyspinw.util.magnetic_symmetry import name_converter
from pyspinw.util.group_generators import parse_one_line_generators



@pytest.mark.parametrize("number", range(1, 1652))
def test_generator_consistency(number: int):
generator_string = name_converter.litvin[number].generators

generators_from_pyspinw_database = parse_one_line_generators(generator_string)


generators_from_spglib = spglib.get_symmetry_from_database(number)

print(generators_from_spglib)
print(generators_from_pyspinw_database)

0 comments on commit c975c45

Please sign in to comment.