Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions news/deprecate-symmetryutilities-3.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
**Added:**

* Added ``equal_positions`` method in ``symmetryutilities.py``
* Added ``expand_position`` method in ``symmetryutilities.py``
* Added ``null_space`` method in ``symmetryutilities.py``

**Changed:**

* <news item>

**Deprecated:**

* Deprecated ``equalPositions`` method in ``symmetryutilities.py`` for removal in version 4.0.0
* Deprecated ``expandPosition`` method in ``symmetryutilities.py`` for removal in version 4.0.0
* Deprecated ``nullSpace`` method in ``symmetryutilities.py`` for removal in version 4.0.0

**Removed:**

* <news item>

**Fixed:**

* <news item>

**Security:**

* <news item>
58 changes: 53 additions & 5 deletions src/diffpy/structure/symmetryutilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@
"nearest_site_index",
removal_version,
)
equalPositions_deprecation_msg = build_deprecation_message(
base,
"equalPositions",
"equal_positions",
removal_version,
)
expandPosition_deprecation_msg = build_deprecation_message(
base,
"expandPosition",
"expand_position",
removal_version,
)
nullSpace_deprecation_msg = build_deprecation_message(
base,
"nullSpace",
"null_space",
removal_version,
)

# Constants ------------------------------------------------------------------

Expand Down Expand Up @@ -299,7 +317,17 @@ def nearest_site_index(sites, xyz):
return nearindex


@deprecated(equalPositions_deprecation_msg)
def equalPositions(xyz0, xyz1, eps):
"""'diffpy.structure.equalPositions' is deprecated and will be
removed in version 4.0.0.
Please use 'diffpy.structure.equal_positions' instead.
"""
return equal_positions(xyz0, xyz1, eps)


def equal_positions(xyz0, xyz1, eps):
"""Equality of two coordinates with optional tolerance.
Parameters
Expand All @@ -319,7 +347,17 @@ def equalPositions(xyz0, xyz1, eps):
return numpy.all(dxyz <= eps)


@deprecated(expandPosition_deprecation_msg)
def expandPosition(spacegroup, xyz, sgoffset=[0, 0, 0], eps=None):
"""'diffpy.structure.expandPosition' is deprecated and will be
removed in version 4.0.0.
Please use 'diffpy.structure.expand_position' instead.
"""
return expand_position(spacegroup, xyz, sgoffset, eps)


def expand_position(spacegroup, xyz, sgoffset=[0, 0, 0], eps=None):
"""Obtain unique equivalent positions and corresponding operations.
Parameters
Expand Down Expand Up @@ -358,7 +396,7 @@ def expandPosition(spacegroup, xyz, sgoffset=[0, 0, 0], eps=None):
if positions:
nearpos = positions[nearest_site_index(positions, pos)]
# is it an equivalent position?
if equalPositions(nearpos, pos, eps):
if equal_positions(nearpos, pos, eps):
# tpl should map to the same list as nearpos
site_symops[tpl] = site_symops[pos2tuple(nearpos)]
pos_is_new = False
Expand All @@ -372,7 +410,17 @@ def expandPosition(spacegroup, xyz, sgoffset=[0, 0, 0], eps=None):
return positions, pos_symops, multiplicity


@deprecated(nullSpace_deprecation_msg)
def nullSpace(A):
"""'diffpy.structure.nullSpace' is deprecated and will be removed in
version 4.0.0.
Please use 'diffpy.structure.null_space' instead.
"""
return null_space(A)


def null_space(A):
"""Null space of matrix A."""
from numpy import linalg

Expand Down Expand Up @@ -588,7 +636,7 @@ def _findNullSpace(self):
R0 = self.invariants[0].R
Rdiff = [(symop.R - R0) for symop in self.invariants]
Rdiff = numpy.concatenate(Rdiff, axis=0)
self.null_space = nullSpace(Rdiff)
self.null_space = null_space(Rdiff)
if self.null_space.size == 0:
return
# reverse sort rows of null_space rows by absolute value
Expand Down Expand Up @@ -649,7 +697,7 @@ def _findUSpace(self):
Ucj2 = numpy.dot(R, numpy.dot(Ucj, R.T))
for i, kl in i6kl:
R6z[i, j] += Ucj2[kl]
Usp6 = nullSpace(R6zall)
Usp6 = null_space(R6zall)
# normalize Usp6 by its maximum component
mxcols = numpy.argmax(numpy.fabs(Usp6), axis=1)
mxrows = numpy.arange(len(mxcols))
Expand Down Expand Up @@ -716,7 +764,7 @@ def positionFormula(self, pos, xyzsymbols=("x", "y", "z")):
# find pos in eqxyz
idx = nearest_site_index(self.eqxyz, pos)
eqpos = self.eqxyz[idx]
if not equalPositions(eqpos, pos, self.eps):
if not equal_positions(eqpos, pos, self.eps):
return {}
# any rotation matrix should do fine
R = self.symops[idx][0].R
Expand Down Expand Up @@ -768,7 +816,7 @@ def UFormula(self, pos, Usymbols=stdUsymbols):
# find pos in eqxyz
idx = nearest_site_index(self.eqxyz, pos)
eqpos = self.eqxyz[idx]
if not equalPositions(eqpos, pos, self.eps):
if not equal_positions(eqpos, pos, self.eps):
return {}
# any rotation matrix should do fine
R = self.symops[idx][0].R
Expand Down
102 changes: 102 additions & 0 deletions tests/test_symmetryutilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@
GeneratorSite,
SymmetryConstraints,
_Position2Tuple,
equal_positions,
equalPositions,
expand_position,
expandPosition,
is_constant_formula,
is_space_group_latt_parms,
isconstantFormula,
isSpaceGroupLatPar,
nearest_site_index,
nearestSiteIndex,
null_space,
nullSpace,
position_difference,
positionDifference,
pruneFormulaDictionary,
Expand Down Expand Up @@ -127,6 +132,17 @@ def test_expandPosition(self):
self.assertEqual(4, pmult)
return

def test_expand_position(self):
"""Check expand_position()"""
# ok again Ni example
fcc = GetSpaceGroup(225)
pos, pops, pmult = expand_position(fcc, [0, 0, 0])
self.assertTrue(numpy.all(pos[0] == 0.0))
self.assertEqual(4, len(pos))
self.assertEqual(192, sum([len(line) for line in pops]))
self.assertEqual(4, pmult)
return

def test_pruneFormulaDictionary(self):
"""Check pruneFormulaDictionary()"""
fmdict = {"x": "3*y-0.17", "y": "0", "z": "0.13"}
Expand All @@ -152,6 +168,12 @@ def test_is_constant_formula(self):
self.assertTrue(is_constant_formula("+13/ 9"))
return

def test_equalPositions(self):
"""Check equalPositions()"""
self.assertTrue(equalPositions([0.1, 0.2, 0.3], [0.1, 0.2, 0.3], 1.0e-5))
self.assertTrue(equalPositions([0.1 + 0.5e-5, 0.2 + 0.5e-5, 0.3 + 0.5e-5], [0.1, 0.2, 0.3], 1.0e-5))
self.assertFalse(equalPositions([0.2, 0.2, 0.3], [0.1, 0.2, 0.3], 1.0e-5))


# End of class TestRoutines

Expand Down Expand Up @@ -704,5 +726,85 @@ def test_nearest_site_index(sites, xyz, expected):
assert actual == expected


@pytest.mark.parametrize(
"xyz0, xyz1, eps, expected",
[
pytest.param([0.1, 0.2, 0.3], [0.1, 0.2, 0.3], 1.0e-5, True), # C1: same position
pytest.param(
[0.1 + 0.5e-5, 0.2 + 0.5e-5, 0.3 + 0.5e-5], [0.1, 0.2, 0.3], 1.0e-5, True
), # C2: same position with some tolerance
pytest.param([0.2, 0.2, 0.3], [0.1, 0.2, 0.3], 1.0e-5, False), # C3: different positions
],
)
def test_equal_positions(xyz0, xyz1, eps, expected):
"""Check equalPositions."""
actual = equal_positions(xyz0, xyz1, eps)
assert actual == expected


@pytest.mark.parametrize(
"A, expected_dim",
[
pytest.param( # C1: full-rank 2x2 matrix
[[1.0, 0.0], [0.0, 1.0]],
0,
),
pytest.param( # C2: Nullspace has dim 1
[[1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.0]],
1,
),
pytest.param( # C3: Nullspace has dim 2
[[1.0, 2.0, 3.0], [2.0, 4.0, 6.0], [0.0, 0.0, 0.0]],
2,
),
pytest.param( # C4: Nullspace has dim 2
[[0.0, 0.0], [0.0, 0.0]],
2,
),
],
)
def test_nullSpace(A, expected_dim):
"""Check nullSpace returns an orthonormal basis on supported square
matrices."""
A = numpy.asarray(A, dtype=float)
actual = nullSpace(A)

assert actual.shape == (expected_dim, A.shape[1])
assert numpy.allclose(A @ actual.T, numpy.zeros((A.shape[0], expected_dim)), atol=1e-12)
assert numpy.allclose(actual @ actual.T, numpy.eye(expected_dim), atol=1e-12)


@pytest.mark.parametrize(
"A, expected_dim",
[
pytest.param( # C1: full-rank 2x2 matrix
[[1.0, 0.0], [0.0, 1.0]],
0,
),
pytest.param( # C2: Nullspace has dim 1
[[1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.0]],
1,
),
pytest.param( # C3: Nullspace has dim 2
[[1.0, 2.0, 3.0], [2.0, 4.0, 6.0], [0.0, 0.0, 0.0]],
2,
),
pytest.param( # C4: Nullspace has dim 2
[[0.0, 0.0], [0.0, 0.0]],
2,
),
],
)
def test_null_space(A, expected_dim):
"""Check null_space returns an orthonormal basis on supported square
matrices."""
A = numpy.asarray(A, dtype=float)
actual = null_space(A)

assert actual.shape == (expected_dim, A.shape[1])
assert numpy.allclose(A @ actual.T, numpy.zeros((A.shape[0], expected_dim)), atol=1e-12)
assert numpy.allclose(actual @ actual.T, numpy.eye(expected_dim), atol=1e-12)


if __name__ == "__main__":
unittest.main()
Loading