From 6bc919883825deda0a776d47414fce0d44becffc Mon Sep 17 00:00:00 2001 From: Jack Greisman Date: Wed, 24 Aug 2022 12:30:46 -0400 Subject: [PATCH 1/5] Add tests for rs.utils.is_polar() using sgtbx --- tests/data/gen_sgtbx_is_polar.py | 21 ++ tests/data/sgtbx/sgtbx_polar.csv | 531 +++++++++++++++++++++++++++++++ tests/utils/test_polar.py | 44 +++ 3 files changed, 596 insertions(+) create mode 100644 tests/data/gen_sgtbx_is_polar.py create mode 100644 tests/data/sgtbx/sgtbx_polar.csv create mode 100644 tests/utils/test_polar.py diff --git a/tests/data/gen_sgtbx_is_polar.py b/tests/data/gen_sgtbx_is_polar.py new file mode 100644 index 00000000..e869fcbd --- /dev/null +++ b/tests/data/gen_sgtbx_is_polar.py @@ -0,0 +1,21 @@ +""" +Generate test data using sgtbx classifications of polar spacegroups +""" + +from cctbx import sgtbx +import pandas as pd + +# Classify all space group settings +is_polar = [] +xhms = [] +for sg in sgtbx.space_group_symbol_iterator(): + sgtbx_polar = ( + sgtbx.space_group(sg).info().number_of_continuous_allowed_origin_shifts() > 0 + ) + xhm = sg.universal_hermann_mauguin() + is_polar.append(sgtbx_polar) + xhms.append(xhm) + +# Write out CSV +df = pd.DataFrame({"xhm": xhms, "is_polar": is_polar}) +df.to_csv("sgtbx/sgtbx_polar.csv", index=None) diff --git a/tests/data/sgtbx/sgtbx_polar.csv b/tests/data/sgtbx/sgtbx_polar.csv new file mode 100644 index 00000000..974e6d9a --- /dev/null +++ b/tests/data/sgtbx/sgtbx_polar.csv @@ -0,0 +1,531 @@ +xhm,is_polar +P 1,True +P -1,False +P 1 2 1,True +P 1 1 2,True +P 2 1 1,True +P 1 21 1,True +P 1 1 21,True +P 21 1 1,True +C 1 2 1,True +A 1 2 1,True +I 1 2 1,True +A 1 1 2,True +B 1 1 2,True +I 1 1 2,True +B 2 1 1,True +C 2 1 1,True +I 2 1 1,True +P 1 m 1,True +P 1 1 m,True +P m 1 1,True +P 1 c 1,True +P 1 n 1,True +P 1 a 1,True +P 1 1 a,True +P 1 1 n,True +P 1 1 b,True +P b 1 1,True +P n 1 1,True +P c 1 1,True +C 1 m 1,True +A 1 m 1,True +I 1 m 1,True +A 1 1 m,True +B 1 1 m,True +I 1 1 m,True +B m 1 1,True +C m 1 1,True +I m 1 1,True +C 1 c 1,True +A 1 n 1,True +I 1 a 1,True +A 1 a 1,True +C 1 n 1,True +I 1 c 1,True +A 1 1 a,True +B 1 1 n,True +I 1 1 b,True +B 1 1 b,True +A 1 1 n,True +I 1 1 a,True +B b 1 1,True +C n 1 1,True +I c 1 1,True +C c 1 1,True +B n 1 1,True +I b 1 1,True +P 1 2/m 1,False +P 1 1 2/m,False +P 2/m 1 1,False +P 1 21/m 1,False +P 1 1 21/m,False +P 21/m 1 1,False +C 1 2/m 1,False +A 1 2/m 1,False +I 1 2/m 1,False +A 1 1 2/m,False +B 1 1 2/m,False +I 1 1 2/m,False +B 2/m 1 1,False +C 2/m 1 1,False +I 2/m 1 1,False +P 1 2/c 1,False +P 1 2/n 1,False +P 1 2/a 1,False +P 1 1 2/a,False +P 1 1 2/n,False +P 1 1 2/b,False +P 2/b 1 1,False +P 2/n 1 1,False +P 2/c 1 1,False +P 1 21/c 1,False +P 1 21/n 1,False +P 1 21/a 1,False +P 1 1 21/a,False +P 1 1 21/n,False +P 1 1 21/b,False +P 21/b 1 1,False +P 21/n 1 1,False +P 21/c 1 1,False +C 1 2/c 1,False +A 1 2/n 1,False +I 1 2/a 1,False +A 1 2/a 1,False +C 1 2/n 1,False +I 1 2/c 1,False +A 1 1 2/a,False +B 1 1 2/n,False +I 1 1 2/b,False +B 1 1 2/b,False +A 1 1 2/n,False +I 1 1 2/a,False +B 2/b 1 1,False +C 2/n 1 1,False +I 2/c 1 1,False +C 2/c 1 1,False +B 2/n 1 1,False +I 2/b 1 1,False +P 2 2 2,False +P 2 2 21,False +P 21 2 2,False +P 2 21 2,False +P 21 21 2,False +P 2 21 21,False +P 21 2 21,False +P 21 21 21,False +C 2 2 21,False +A 21 2 2,False +B 2 21 2,False +C 2 2 2,False +A 2 2 2,False +B 2 2 2,False +F 2 2 2,False +I 2 2 2,False +I 21 21 21,False +P m m 2,True +P 2 m m,True +P m 2 m,True +P m c 21,True +P c m 21,True +P 21 m a,True +P 21 a m,True +P b 21 m,True +P m 21 b,True +P c c 2,True +P 2 a a,True +P b 2 b,True +P m a 2,True +P b m 2,True +P 2 m b,True +P 2 c m,True +P c 2 m,True +P m 2 a,True +P c a 21,True +P b c 21,True +P 21 a b,True +P 21 c a,True +P c 21 b,True +P b 21 a,True +P n c 2,True +P c n 2,True +P 2 n a,True +P 2 a n,True +P b 2 n,True +P n 2 b,True +P m n 21,True +P n m 21,True +P 21 m n,True +P 21 n m,True +P n 21 m,True +P m 21 n,True +P b a 2,True +P 2 c b,True +P c 2 a,True +P n a 21,True +P b n 21,True +P 21 n b,True +P 21 c n,True +P c 21 n,True +P n 21 a,True +P n n 2,True +P 2 n n,True +P n 2 n,True +C m m 2,True +A 2 m m,True +B m 2 m,True +C m c 21,True +C c m 21,True +A 21 m a,True +A 21 a m,True +B b 21 m,True +B m 21 b,True +C c c 2,True +A 2 a a,True +B b 2 b,True +A m m 2,True +B m m 2,True +B 2 m m,True +C 2 m m,True +C m 2 m,True +A m 2 m,True +A b m 2,True +B m a 2,True +B 2 c m,True +C 2 m b,True +C m 2 a,True +A c 2 m,True +A m a 2,True +B b m 2,True +B 2 m b,True +C 2 c m,True +C c 2 m,True +A m 2 a,True +A b a 2,True +B b a 2,True +B 2 c b,True +C 2 c b,True +C c 2 a,True +A c 2 a,True +F m m 2,True +F 2 m m,True +F m 2 m,True +F d d 2,True +F 2 d d,True +F d 2 d,True +I m m 2,True +I 2 m m,True +I m 2 m,True +I b a 2,True +I 2 c b,True +I c 2 a,True +I m a 2,True +I b m 2,True +I 2 m b,True +I 2 c m,True +I c 2 m,True +I m 2 a,True +P m m m,False +P n n n :1,False +P n n n :2,False +P c c m,False +P m a a,False +P b m b,False +P b a n :1,False +P b a n :2,False +P n c b :1,False +P n c b :2,False +P c n a :1,False +P c n a :2,False +P m m a,False +P m m b,False +P b m m,False +P c m m,False +P m c m,False +P m a m,False +P n n a,False +P n n b,False +P b n n,False +P c n n,False +P n c n,False +P n a n,False +P m n a,False +P n m b,False +P b m n,False +P c n m,False +P n c m,False +P m a n,False +P c c a,False +P c c b,False +P b a a,False +P c a a,False +P b c b,False +P b a b,False +P b a m,False +P m c b,False +P c m a,False +P c c n,False +P n a a,False +P b n b,False +P b c m,False +P c a m,False +P m c a,False +P m a b,False +P b m a,False +P c m b,False +P n n m,False +P m n n,False +P n m n,False +P m m n :1,False +P m m n :2,False +P n m m :1,False +P n m m :2,False +P m n m :1,False +P m n m :2,False +P b c n,False +P c a n,False +P n c a,False +P n a b,False +P b n a,False +P c n b,False +P b c a,False +P c a b,False +P n m a,False +P m n b,False +P b n m,False +P c m n,False +P m c n,False +P n a m,False +C m c m,False +C c m m,False +A m m a,False +A m a m,False +B b m m,False +B m m b,False +C m c a,False +C c m b,False +A b m a,False +A c a m,False +B b c m,False +B m a b,False +C m m m,False +A m m m,False +B m m m,False +C c c m,False +A m a a,False +B b m b,False +C m m a,False +C m m b,False +A b m m,False +A c m m,False +B m c m,False +B m a m,False +C c c a :1,False +C c c a :2,False +C c c b :1,False +C c c b :2,False +A b a a :1,False +A b a a :2,False +A c a a :1,False +A c a a :2,False +B b c b :1,False +B b c b :2,False +B b a b :1,False +B b a b :2,False +F m m m,False +F d d d :1,False +F d d d :2,False +I m m m,False +I b a m,False +I m c b,False +I c m a,False +I b c a,False +I c a b,False +I m m a,False +I m m b,False +I b m m,False +I c m m,False +I m c m,False +I m a m,False +P 4,True +P 41,True +P 42,True +P 43,True +I 4,True +I 41,True +P -4,False +I -4,False +P 4/m,False +P 42/m,False +P 4/n :1,False +P 4/n :2,False +P 42/n :1,False +P 42/n :2,False +I 4/m,False +I 41/a :1,False +I 41/a :2,False +P 4 2 2,False +P 4 21 2,False +P 41 2 2,False +P 41 21 2,False +P 42 2 2,False +P 42 21 2,False +P 43 2 2,False +P 43 21 2,False +I 4 2 2,False +I 41 2 2,False +P 4 m m,True +P 4 b m,True +P 42 c m,True +P 42 n m,True +P 4 c c,True +P 4 n c,True +P 42 m c,True +P 42 b c,True +I 4 m m,True +I 4 c m,True +I 41 m d,True +I 41 c d,True +P -4 2 m,False +P -4 2 c,False +P -4 21 m,False +P -4 21 c,False +P -4 m 2,False +P -4 c 2,False +P -4 b 2,False +P -4 n 2,False +I -4 m 2,False +I -4 c 2,False +I -4 2 m,False +I -4 2 d,False +P 4/m m m,False +P 4/m c c,False +P 4/n b m :1,False +P 4/n b m :2,False +P 4/n n c :1,False +P 4/n n c :2,False +P 4/m b m,False +P 4/m n c,False +P 4/n m m :1,False +P 4/n m m :2,False +P 4/n c c :1,False +P 4/n c c :2,False +P 42/m m c,False +P 42/m c m,False +P 42/n b c :1,False +P 42/n b c :2,False +P 42/n n m :1,False +P 42/n n m :2,False +P 42/m b c,False +P 42/m n m,False +P 42/n m c :1,False +P 42/n m c :2,False +P 42/n c m :1,False +P 42/n c m :2,False +I 4/m m m,False +I 4/m c m,False +I 41/a m d :1,False +I 41/a m d :2,False +I 41/a c d :1,False +I 41/a c d :2,False +P 3,True +P 31,True +P 32,True +R 3 :H,True +R 3 :R,True +P -3,False +R -3 :H,False +R -3 :R,False +P 3 1 2,False +P 3 2 1,False +P 31 1 2,False +P 31 2 1,False +P 32 1 2,False +P 32 2 1,False +R 3 2 :H,False +R 3 2 :R,False +P 3 m 1,True +P 3 1 m,True +P 3 c 1,True +P 3 1 c,True +R 3 m :H,True +R 3 m :R,True +R 3 c :H,True +R 3 c :R,True +P -3 1 m,False +P -3 1 c,False +P -3 m 1,False +P -3 c 1,False +R -3 m :H,False +R -3 m :R,False +R -3 c :H,False +R -3 c :R,False +P 6,True +P 61,True +P 65,True +P 62,True +P 64,True +P 63,True +P -6,False +P 6/m,False +P 63/m,False +P 6 2 2,False +P 61 2 2,False +P 65 2 2,False +P 62 2 2,False +P 64 2 2,False +P 63 2 2,False +P 6 m m,True +P 6 c c,True +P 63 c m,True +P 63 m c,True +P -6 m 2,False +P -6 c 2,False +P -6 2 m,False +P -6 2 c,False +P 6/m m m,False +P 6/m c c,False +P 63/m c m,False +P 63/m m c,False +P 2 3,False +F 2 3,False +I 2 3,False +P 21 3,False +I 21 3,False +P m -3,False +P n -3 :1,False +P n -3 :2,False +F m -3,False +F d -3 :1,False +F d -3 :2,False +I m -3,False +P a -3,False +I a -3,False +P 4 3 2,False +P 42 3 2,False +F 4 3 2,False +F 41 3 2,False +I 4 3 2,False +P 43 3 2,False +P 41 3 2,False +I 41 3 2,False +P -4 3 m,False +F -4 3 m,False +I -4 3 m,False +P -4 3 n,False +F -4 3 c,False +I -4 3 d,False +P m -3 m,False +P n -3 n :1,False +P n -3 n :2,False +P m -3 n,False +P n -3 m :1,False +P n -3 m :2,False +F m -3 m,False +F m -3 c,False +F d -3 m :1,False +F d -3 m :2,False +F d -3 c :1,False +F d -3 c :2,False +I m -3 m,False +I a -3 d,False diff --git a/tests/utils/test_polar.py b/tests/utils/test_polar.py new file mode 100644 index 00000000..d31d1a10 --- /dev/null +++ b/tests/utils/test_polar.py @@ -0,0 +1,44 @@ +from os.path import abspath, dirname, join + +import gemmi +import pandas as pd +import pytest +import reciprocalspaceship as rs + + +def sgtbx_polar_classification(): + """ + Helper function for generating Hermann-Mauguin (xhm) symbols with + corresponding polar classifications + """ + data = ["..", "data", "sgtbx", "sgtbx_polar.csv"] + inFN = abspath(join(dirname(__file__), *data)) + ref = pd.read_csv(inFN) + return ref.iterrows() + + +@pytest.fixture(params=sgtbx_polar_classification()) +def polar_by_xhm(request): + """ + sgtbx classifications of whether spacegroup settings are polar. + + Yields + ------ + Tuple(xhm_str, is_polar_bool) + xhm symbol and is_polar classification + """ + i, row = request.param + return row["xhm"], row["is_polar"] + + +@pytest.mark.parametrize("use_gemmi_obj", [True, False]) +def test_is_polar(polar_by_xhm, use_gemmi_obj): + """ + Test rs.utils.is_polar() with xhm strings and gemmi.SpaceGroup objects + """ + xhm, sgtbx_is_polar = polar_by_xhm + + if use_gemmi_obj: + assert sgtbx_is_polar == rs.utils.is_polar(gemmi.SpaceGroup(xhm)) + else: + assert sgtbx_is_polar == rs.utils.is_polar(xhm) From 2dae74e5c138eda6d441c31a997ffab2c3cd4806 Mon Sep 17 00:00:00 2001 From: Jack Greisman Date: Wed, 24 Aug 2022 12:31:12 -0400 Subject: [PATCH 2/5] Implement rs.utils.is_polar() and rename utils.symop to utils.symmetry --- reciprocalspaceship/utils/__init__.py | 2 +- reciprocalspaceship/utils/asu.py | 2 +- reciprocalspaceship/utils/phases.py | 2 +- .../utils/{symop.py => symmetry.py} | 21 +++++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) rename reciprocalspaceship/utils/{symop.py => symmetry.py} (74%) diff --git a/reciprocalspaceship/utils/__init__.py b/reciprocalspaceship/utils/__init__.py index a57cdac3..aba59e6d 100644 --- a/reciprocalspaceship/utils/__init__.py +++ b/reciprocalspaceship/utils/__init__.py @@ -42,5 +42,5 @@ is_centric, to_structurefactor, ) -from reciprocalspaceship.utils.symop import apply_to_hkl, phase_shift +from reciprocalspaceship.utils.symmetry import apply_to_hkl, is_polar, phase_shift from reciprocalspaceship.utils.units import angstroms2ev, ev2angstroms diff --git a/reciprocalspaceship/utils/asu.py b/reciprocalspaceship/utils/asu.py index e6fda21c..937f8c50 100644 --- a/reciprocalspaceship/utils/asu.py +++ b/reciprocalspaceship/utils/asu.py @@ -4,7 +4,7 @@ from reciprocalspaceship.decorators import cellify, spacegroupify from reciprocalspaceship.utils.cell import generate_reciprocal_cell from reciprocalspaceship.utils.structurefactors import is_absent, is_centric -from reciprocalspaceship.utils.symop import apply_to_hkl, phase_shift +from reciprocalspaceship.utils.symmetry import apply_to_hkl, phase_shift # fmt: off ccp4_hkl_asu = [ diff --git a/reciprocalspaceship/utils/phases.py b/reciprocalspaceship/utils/phases.py index 3bc266a5..cab1ce9d 100644 --- a/reciprocalspaceship/utils/phases.py +++ b/reciprocalspaceship/utils/phases.py @@ -40,7 +40,7 @@ def get_phase_restrictions(H, spacegroup): list is returned for Miller indices without phase restrictions """ from reciprocalspaceship.utils.asu import is_absent, is_centric - from reciprocalspaceship.utils.symop import apply_to_hkl, phase_shift + from reciprocalspaceship.utils.symmetry import apply_to_hkl, phase_shift friedel_op = gemmi.Op("-x,-y,-z") # Grabs all the non-identity symops diff --git a/reciprocalspaceship/utils/symop.py b/reciprocalspaceship/utils/symmetry.py similarity index 74% rename from reciprocalspaceship/utils/symop.py rename to reciprocalspaceship/utils/symmetry.py index 4e5c275c..6b8595e4 100644 --- a/reciprocalspaceship/utils/symop.py +++ b/reciprocalspaceship/utils/symmetry.py @@ -1,4 +1,5 @@ import numpy as np +from reciprocalspaceship.decorators import spacegroupify def apply_to_hkl(H, op): @@ -56,3 +57,23 @@ def phase_shift(H, op): array of phase shifts """ return -2 * np.pi * np.matmul(H, op.tran) / op.DEN + + +@spacegroupify +def is_polar(spacegroup): + """ + Classify whether spacegroup is polar + + Parameters + ---------- + spacegroup : str, int, gemmi.SpaceGroup + Spacegroup to classify as polar + + Returns + ------- + bool + Whether the spacegroup is polar + """ + sym_ops = spacegroup.operations().sym_ops + a = np.array([op.rot for op in sym_ops]) + return ~(a < 0).any(axis=2).any(axis=0).all() From 9a2070ba4b5f2cf78c702e4b6a89b2659317a531 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Aug 2022 16:37:29 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- reciprocalspaceship/utils/symmetry.py | 1 + tests/data/gen_sgtbx_is_polar.py | 2 +- tests/utils/test_polar.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/reciprocalspaceship/utils/symmetry.py b/reciprocalspaceship/utils/symmetry.py index 6b8595e4..58c619dd 100644 --- a/reciprocalspaceship/utils/symmetry.py +++ b/reciprocalspaceship/utils/symmetry.py @@ -1,4 +1,5 @@ import numpy as np + from reciprocalspaceship.decorators import spacegroupify diff --git a/tests/data/gen_sgtbx_is_polar.py b/tests/data/gen_sgtbx_is_polar.py index e869fcbd..c92dd2a1 100644 --- a/tests/data/gen_sgtbx_is_polar.py +++ b/tests/data/gen_sgtbx_is_polar.py @@ -2,8 +2,8 @@ Generate test data using sgtbx classifications of polar spacegroups """ -from cctbx import sgtbx import pandas as pd +from cctbx import sgtbx # Classify all space group settings is_polar = [] diff --git a/tests/utils/test_polar.py b/tests/utils/test_polar.py index d31d1a10..058d50d1 100644 --- a/tests/utils/test_polar.py +++ b/tests/utils/test_polar.py @@ -3,6 +3,7 @@ import gemmi import pandas as pd import pytest + import reciprocalspaceship as rs From 0836144a37953985470ac9c18d275ff821165cb0 Mon Sep 17 00:00:00 2001 From: Jack Greisman Date: Wed, 24 Aug 2022 17:04:25 -0400 Subject: [PATCH 4/5] Update docstring of pytest fixtures --- reciprocalspaceship/utils/symmetry.py | 1 + tests/data/gen_sgtbx_is_polar.py | 2 +- tests/utils/test_polar.py | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/reciprocalspaceship/utils/symmetry.py b/reciprocalspaceship/utils/symmetry.py index 6b8595e4..58c619dd 100644 --- a/reciprocalspaceship/utils/symmetry.py +++ b/reciprocalspaceship/utils/symmetry.py @@ -1,4 +1,5 @@ import numpy as np + from reciprocalspaceship.decorators import spacegroupify diff --git a/tests/data/gen_sgtbx_is_polar.py b/tests/data/gen_sgtbx_is_polar.py index e869fcbd..c92dd2a1 100644 --- a/tests/data/gen_sgtbx_is_polar.py +++ b/tests/data/gen_sgtbx_is_polar.py @@ -2,8 +2,8 @@ Generate test data using sgtbx classifications of polar spacegroups """ -from cctbx import sgtbx import pandas as pd +from cctbx import sgtbx # Classify all space group settings is_polar = [] diff --git a/tests/utils/test_polar.py b/tests/utils/test_polar.py index d31d1a10..cab18aa5 100644 --- a/tests/utils/test_polar.py +++ b/tests/utils/test_polar.py @@ -3,13 +3,19 @@ import gemmi import pandas as pd import pytest + import reciprocalspaceship as rs def sgtbx_polar_classification(): """ - Helper function for generating Hermann-Mauguin (xhm) symbols with - corresponding polar classifications + Helper function for iterating over Hermann-Mauguin (xhm) symbols with + corresponding polar classifications. + + Yields + ------ + Tuple(int, pd.Series) + Row index and pd.Series with values of row in pd.DataFrame """ data = ["..", "data", "sgtbx", "sgtbx_polar.csv"] inFN = abspath(join(dirname(__file__), *data)) @@ -20,12 +26,14 @@ def sgtbx_polar_classification(): @pytest.fixture(params=sgtbx_polar_classification()) def polar_by_xhm(request): """ - sgtbx classifications of whether spacegroup settings are polar. + Fixture function that parametrizes over sgtbx polar classifications + of each space group setting. This fixture takes the sgtbx_polar_classification() + iterable and packages each as a (xhm, bool) tuple. Yields ------ - Tuple(xhm_str, is_polar_bool) - xhm symbol and is_polar classification + Tuple(str, bool) + xhm symbol and whether corresponding space group is polar """ i, row = request.param return row["xhm"], row["is_polar"] From 3e838ae2d07901571edc034345fa28566996bd64 Mon Sep 17 00:00:00 2001 From: Jack Greisman Date: Thu, 25 Aug 2022 10:36:04 -0400 Subject: [PATCH 5/5] Change axis of `any()` call for clarity (both work) --- reciprocalspaceship/utils/symmetry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reciprocalspaceship/utils/symmetry.py b/reciprocalspaceship/utils/symmetry.py index 58c619dd..6e0c2f7c 100644 --- a/reciprocalspaceship/utils/symmetry.py +++ b/reciprocalspaceship/utils/symmetry.py @@ -77,4 +77,4 @@ def is_polar(spacegroup): """ sym_ops = spacegroup.operations().sym_ops a = np.array([op.rot for op in sym_ops]) - return ~(a < 0).any(axis=2).any(axis=0).all() + return ~(a < 0).any(axis=1).any(axis=0).all()