Skip to content

Commit ad7e720

Browse files
authored
Merge pull request #181 from stevenhua0320/deprecate-atom
chore: deprecate Atom class method
2 parents b73f794 + d6d8525 commit ad7e720

File tree

3 files changed

+240
-26
lines changed

3 files changed

+240
-26
lines changed

news/deprecate-atom.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
**Added:**
2+
3+
* Added ``msd_latt`` method in ``atom.py``
4+
* Added ``msd_cart`` method in ``atom.py``
5+
* Added ``_get_uij`` method in ``atom.py``
6+
* Added ``_set_uij`` method in ``atom.py``
7+
8+
9+
**Changed:**
10+
11+
* <news item>
12+
13+
**Deprecated:**
14+
15+
* Deprecated ``msdLat`` method in ``atom.py`` for removal in version 4.0.0
16+
* Deprecated ``msdCart`` method in ``atom.py`` for removal in version 4.0.0
17+
18+
**Removed:**
19+
20+
* <news item>
21+
22+
**Fixed:**
23+
24+
* <news item>
25+
26+
**Security:**
27+
28+
* <news item>

src/diffpy/structure/atom.py

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,27 @@
1818
import numpy
1919

2020
from diffpy.structure.lattice import cartesian as cartesian_lattice
21+
from diffpy.utils._deprecator import build_deprecation_message, deprecated
2122

2223
# conversion constants
2324
_BtoU = 1.0 / (8 * numpy.pi**2)
2425
_UtoB = 1.0 / _BtoU
2526

2627
# ----------------------------------------------------------------------------
28+
base = "diffpy.structure.Atom"
29+
removal_version = "4.0.0"
30+
msdLat_deprecation_msg = build_deprecation_message(
31+
base,
32+
"msdLat",
33+
"msd_latt",
34+
removal_version,
35+
)
36+
msdCart_deprecation_msg = build_deprecation_message(
37+
base,
38+
"msdCart",
39+
"msd_cart",
40+
removal_version,
41+
)
2742

2843

2944
class Atom(object):
@@ -149,7 +164,16 @@ def __init__(
149164
self.anisotropy = bool(anisotropy)
150165
return
151166

167+
@deprecated(msdLat_deprecation_msg)
152168
def msdLat(self, vl):
169+
"""This function has been deprecated and will be removed in
170+
version 4.0.0.
171+
172+
Please use diffpy.structure.Atom.msd_latt instead.
173+
"""
174+
return self.msd_latt(vl)
175+
176+
def msd_latt(self, vl):
153177
"""Calculate mean square displacement along the lattice vector.
154178
155179
Parameters
@@ -173,7 +197,16 @@ def msdLat(self, vl):
173197
msd = numpy.dot(rhs, numpy.dot(self.U, rhs))
174198
return msd
175199

200+
@deprecated(msdLat_deprecation_msg)
176201
def msdCart(self, vc):
202+
"""This function has been deprecated and will be removed in
203+
version 4.0.0.
204+
205+
Please use diffpy.structure.Atom.msd_cart instead.
206+
"""
207+
return self.msd_cart(vc)
208+
209+
def msd_cart(self, vc):
177210
"""Calculate mean square displacement along the Cartesian
178211
vector.
179212
@@ -336,14 +369,14 @@ def U(self, value):
336369

337370
# Uij elements
338371

339-
def _get_Uij(self, i, j):
372+
def _get_uij(self, i, j):
340373
"""The getter function for the `U11`, `U22`, ..., properties."""
341374
if self.anisotropy:
342375
return self._U[i, j]
343376
lat = self.lattice or cartesian_lattice
344377
return self._U[0, 0] * lat.isotropicunit[i, j]
345378

346-
def _set_Uij(self, i, j, value):
379+
def _set_uij(self, i, j, value):
347380
"""The setter function for the `U11`, `U22`, ..., properties."""
348381
self._U[i, j] = value
349382
self._U[j, i] = value
@@ -361,18 +394,18 @@ def _set_Uij(self, i, j, value):
361394
"""
362395

363396
U11 = property(
364-
lambda self: self._get_Uij(0, 0),
365-
lambda self, value: self._set_Uij(0, 0, value),
397+
lambda self: self._get_uij(0, 0),
398+
lambda self, value: self._set_uij(0, 0, value),
366399
doc=_doc_uii.format(0),
367400
)
368401
U22 = property(
369-
lambda self: self._get_Uij(1, 1),
370-
lambda self, value: self._set_Uij(1, 1, value),
402+
lambda self: self._get_uij(1, 1),
403+
lambda self, value: self._set_uij(1, 1, value),
371404
doc=_doc_uii.format(1),
372405
)
373406
U33 = property(
374-
lambda self: self._get_Uij(2, 2),
375-
lambda self, value: self._set_Uij(2, 2, value),
407+
lambda self: self._get_uij(2, 2),
408+
lambda self, value: self._set_uij(2, 2, value),
376409
doc=_doc_uii.format(2),
377410
)
378411

@@ -384,18 +417,18 @@ def _set_Uij(self, i, j, value):
384417
"""
385418

386419
U12 = property(
387-
lambda self: self._get_Uij(0, 1),
388-
lambda self, value: self._set_Uij(0, 1, value),
420+
lambda self: self._get_uij(0, 1),
421+
lambda self, value: self._set_uij(0, 1, value),
389422
doc=_doc_uij.format(0, 1),
390423
)
391424
U13 = property(
392-
lambda self: self._get_Uij(0, 2),
393-
lambda self, value: self._set_Uij(0, 2, value),
425+
lambda self: self._get_uij(0, 2),
426+
lambda self, value: self._set_uij(0, 2, value),
394427
doc=_doc_uij.format(0, 2),
395428
)
396429
U23 = property(
397-
lambda self: self._get_Uij(1, 2),
398-
lambda self, value: self._set_Uij(1, 2, value),
430+
lambda self: self._get_uij(1, 2),
431+
lambda self, value: self._set_uij(1, 2, value),
399432
doc=_doc_uij.format(1, 2),
400433
)
401434

@@ -463,33 +496,33 @@ def Uisoequiv(self, value):
463496
"""
464497

465498
B11 = property(
466-
lambda self: _UtoB * self._get_Uij(0, 0),
467-
lambda self, value: self._set_Uij(0, 0, _BtoU * value),
499+
lambda self: _UtoB * self._get_uij(0, 0),
500+
lambda self, value: self._set_uij(0, 0, _BtoU * value),
468501
doc=_doc_bii.format(1),
469502
)
470503
B22 = property(
471-
lambda self: _UtoB * self._get_Uij(1, 1),
472-
lambda self, value: self._set_Uij(1, 1, _BtoU * value),
504+
lambda self: _UtoB * self._get_uij(1, 1),
505+
lambda self, value: self._set_uij(1, 1, _BtoU * value),
473506
doc=_doc_bii.format(2),
474507
)
475508
B33 = property(
476-
lambda self: _UtoB * self._get_Uij(2, 2),
477-
lambda self, value: self._set_Uij(2, 2, _BtoU * value),
509+
lambda self: _UtoB * self._get_uij(2, 2),
510+
lambda self, value: self._set_uij(2, 2, _BtoU * value),
478511
doc=_doc_bii.format(3),
479512
)
480513
B12 = property(
481-
lambda self: _UtoB * self._get_Uij(0, 1),
482-
lambda self, value: self._set_Uij(0, 1, _BtoU * value),
514+
lambda self: _UtoB * self._get_uij(0, 1),
515+
lambda self, value: self._set_uij(0, 1, _BtoU * value),
483516
doc=_doc_bij.format(1, 2),
484517
)
485518
B13 = property(
486-
lambda self: _UtoB * self._get_Uij(0, 2),
487-
lambda self, value: self._set_Uij(0, 2, _BtoU * value),
519+
lambda self: _UtoB * self._get_uij(0, 2),
520+
lambda self, value: self._set_uij(0, 2, _BtoU * value),
488521
doc=_doc_bij.format(1, 3),
489522
)
490523
B23 = property(
491-
lambda self: _UtoB * self._get_Uij(1, 2),
492-
lambda self, value: self._set_Uij(1, 2, _BtoU * value),
524+
lambda self: _UtoB * self._get_uij(1, 2),
525+
lambda self, value: self._set_uij(1, 2, _BtoU * value),
493526
doc=_doc_bij.format(2, 3),
494527
)
495528

tests/test_atom.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import unittest
1919

2020
import numpy
21+
import pytest
2122

2223
from diffpy.structure.atom import Atom
2324
from diffpy.structure.lattice import Lattice
@@ -74,6 +75,48 @@ def test___init__(self):
7475
# """
7576
# return
7677

78+
def test_msdLat(self):
79+
"""Check Atom.msdLat."""
80+
hexagonal = Lattice(1, 1, 1, 90, 90, 120)
81+
atom_1 = Atom("C", [0, 0, 0], lattice=hexagonal, Uisoequiv=0.0123)
82+
assert atom_1.msdLat([1, 2, 3]) == pytest.approx(0.0123, rel=0, abs=1e-15)
83+
assert atom_1.msdLat([9, 0, -4]) == pytest.approx(0.0123, rel=0, abs=1e-15)
84+
U = numpy.array(
85+
[
86+
[0.010, 0.002, 0.001],
87+
[0.002, 0.020, 0.003],
88+
[0.001, 0.003, 0.030],
89+
],
90+
dtype=float,
91+
)
92+
atom_2 = Atom("C", [0, 0, 0], lattice=hexagonal, U=U)
93+
94+
vc = numpy.array([1.2, -0.3, 0.7], dtype=float)
95+
vl = hexagonal.fractional(vc)
96+
97+
assert atom_2.msdLat(vl) == pytest.approx(atom_2.msd_cart(vc), rel=1e-13, abs=1e-13)
98+
99+
def test_msdCart(self):
100+
"""Check Atom.msdCart."""
101+
hexagonal = Lattice(1, 1, 1, 90, 90, 120)
102+
atom_1 = Atom("C", [0, 0, 0], lattice=hexagonal, Uisoequiv=0.0456)
103+
assert atom_1.msdCart([1, 0, 0]) == pytest.approx(0.0456, rel=0, abs=1e-15)
104+
assert atom_1.msdCart([0, 5, -2]) == pytest.approx(0.0456, rel=0, abs=1e-15)
105+
assert atom_1.msdCart([0, 5, -2]) == pytest.approx(0.0456, rel=0, abs=1e-15)
106+
107+
U = numpy.array(
108+
[
109+
[0.011, 0.001, 0.000],
110+
[0.001, 0.019, 0.002],
111+
[0.000, 0.002, 0.027],
112+
],
113+
dtype=float,
114+
)
115+
atom_2 = Atom("C", [0, 0, 0], lattice=hexagonal, U=U)
116+
117+
vc = numpy.array([0.4, 1.1, -0.6], dtype=float)
118+
assert atom_2.msdCart(vc) == pytest.approx(atom_2.msdCart(3.7 * vc), rel=1e-13, abs=1e-13)
119+
77120
def test_xyz_cartn(self):
78121
"""Check Atom.xyz_cartn property."""
79122
hexagonal = Lattice(1, 1, 1, 90, 90, 120)
@@ -146,7 +189,117 @@ def test_xyz_cartn(self):
146189

147190
# End of class TestAtom
148191

192+
149193
# ----------------------------------------------------------------------------
194+
@pytest.mark.parametrize(
195+
"uiso, lattice_vector",
196+
[ # C1: isotropic displacement, msd is direction-independent in lattice coordinates.
197+
# Expected the msd_latt equals Uisoequiv for any direction.
198+
(0.0123, [1, 2, 3]),
199+
],
200+
)
201+
def test_msd_latt_isotropic(uiso, lattice_vector):
202+
"""Check Atom.msd_latt()."""
203+
hexagonal = Lattice(1, 1, 1, 90, 90, 120)
204+
atom = Atom("C", [0, 0, 0], lattice=hexagonal, Uisoequiv=uiso)
205+
actual = atom.msd_latt(lattice_vector)
206+
expected = pytest.approx(uiso, rel=0, abs=1e-15)
207+
assert actual == expected
208+
209+
210+
@pytest.mark.parametrize(
211+
"U, cartesian_vector",
212+
[ # C2: anisotropic displacement with same physical direction expressed in lattice vs cartesian coords
213+
# Expected msd_latt(fractional(cartesian_vector)) == msd_cart(cartesian_vector)
214+
(
215+
numpy.array(
216+
[
217+
[0.010, 0.002, 0.001],
218+
[0.002, 0.020, 0.003],
219+
[0.001, 0.003, 0.030],
220+
],
221+
dtype=float,
222+
),
223+
numpy.array([1.2, -0.3, 0.7], dtype=float),
224+
),
225+
(
226+
numpy.array(
227+
[
228+
[0.018, -0.001, 0.002],
229+
[-0.001, 0.012, 0.004],
230+
[0.002, 0.004, 0.025],
231+
],
232+
dtype=float,
233+
),
234+
numpy.array([-0.8, 0.9, 0.1], dtype=float),
235+
),
236+
],
237+
)
238+
def test_msd_latt_anisotropic(U, cartesian_vector):
239+
"""Check Atom.msd_latt() anisotropic coordinate-invariance."""
240+
hexagonal = Lattice(1, 1, 1, 90, 90, 120)
241+
atom = Atom("C", [0, 0, 0], lattice=hexagonal, U=U)
242+
lattice_vector = hexagonal.fractional(cartesian_vector)
243+
actual = atom.msd_latt(lattice_vector)
244+
expected = pytest.approx(atom.msd_cart(cartesian_vector), rel=1e-13, abs=1e-13)
245+
assert actual == expected
246+
247+
248+
@pytest.mark.parametrize(
249+
"uiso, cartesian_vector",
250+
[ # C1: isotropic displacement with msd is direction-independent in cartesian coordinates
251+
# Expected msd_cart equals Uisoequiv for any direction
252+
(0.0456, [0, 5, -2]),
253+
],
254+
)
255+
def test_msd_cart_isotropic(uiso, cartesian_vector):
256+
"""Check Atom.msd_cart()."""
257+
hexagonal = Lattice(1, 1, 1, 90, 90, 120)
258+
atom = Atom("C", [0, 0, 0], lattice=hexagonal, Uisoequiv=uiso)
259+
260+
actual = atom.msd_cart(cartesian_vector)
261+
expected = pytest.approx(uiso, rel=0, abs=1e-15)
262+
assert actual == expected
263+
264+
265+
@pytest.mark.parametrize(
266+
"U, cartesian_vector, scale",
267+
[ # C2: anisotropic displacement with msd_cart normalizes direction vector internally
268+
# Expected msd_cart(cartesian_vector) == msd_cart(scale * cartesian_vector)
269+
(
270+
numpy.array(
271+
[
272+
[0.011, 0.001, 0.000],
273+
[0.001, 0.019, 0.002],
274+
[0.000, 0.002, 0.027],
275+
],
276+
dtype=float,
277+
),
278+
numpy.array([0.4, 1.1, -0.6], dtype=float),
279+
3.7,
280+
),
281+
(
282+
numpy.array(
283+
[
284+
[0.020, 0.003, -0.001],
285+
[0.003, 0.014, 0.002],
286+
[-0.001, 0.002, 0.009],
287+
],
288+
dtype=float,
289+
),
290+
numpy.array([2.0, -1.0, 0.5], dtype=float),
291+
0.25,
292+
),
293+
],
294+
)
295+
def test_msd_cart_anisotropic(U, cartesian_vector, scale):
296+
"""Check Atom.msd_cart() anisotropic normalization invariance."""
297+
hexagonal = Lattice(1, 1, 1, 90, 90, 120)
298+
atom = Atom("C", [0, 0, 0], lattice=hexagonal, U=U)
299+
actual = atom.msd_cart(cartesian_vector)
300+
expected = pytest.approx(atom.msd_cart(scale * cartesian_vector), rel=1e-13, abs=1e-13)
301+
assert actual == expected
302+
150303

151304
if __name__ == "__main__":
152305
unittest.main()

0 commit comments

Comments
 (0)