Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
5790740
add attribute 'sort' to atomgroup
1ut Mar 24, 2021
c9326a3
Edit CHANGELOG
1ut Mar 24, 2021
99d6d70
delete white space according to PEP8
1ut Mar 24, 2021
315080c
Edit docs
1ut Mar 25, 2021
6ff70a0
add a test for atomgroup.sort
1ut Mar 25, 2021
dfe7027
add changes to atomgroup.sort
1ut Mar 29, 2021
c86db7a
add changes to test case for atomgroup.sort
1ut Mar 29, 2021
6db489e
edit CHANGELOG
1ut Mar 29, 2021
8b46557
made np.argsort stable
1ut Mar 29, 2021
b3f0455
Add tests for TestAtomGroupSort
1ut Mar 29, 2021
267a1b4
add my name to author list of changelog
1ut Mar 29, 2021
c6d048f
Treat with multiple dimensional array
1ut Mar 31, 2021
044a302
Add testsa for multiple dimensional array
1ut Mar 31, 2021
a8b10b0
Check if number of atoms and idx have a same size.
1ut Apr 1, 2021
b6b9ab4
Add tests for non-number of atoms sized attributes
1ut Apr 1, 2021
2a64457
Stop checking if idx is 0 dimension array
1ut Apr 1, 2021
c2e615a
add pr number to CHANGELOG
1ut Apr 2, 2021
06056e8
Simplify an example in the docs
1ut Apr 4, 2021
6cf9002
Add description of kind in argsort
1ut Apr 4, 2021
fa89e4b
removed unnecessary variable
1ut Apr 4, 2021
5dceb3e
pep8
1ut Apr 4, 2021
88a5953
Add match arguments to pytest
1ut Apr 4, 2021
a72c726
fix tests that not worked
1ut Apr 5, 2021
8628c51
Merge branch 'develop' into sortdev
IAlibay Apr 6, 2021
4f9b588
Merge branch 'develop' into sortdev
1ut Apr 7, 2021
54b0965
pep8
1ut Apr 7, 2021
2fdb7c9
Merge branch 'sortdev' of https://github.com/1ut/mdanalysis into sortdev
1ut Apr 7, 2021
072a1fa
Merge branch 'develop' into sortdev
1ut Apr 7, 2021
cc981ad
improve docs
1ut Apr 7, 2021
cf100fd
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
53da213
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
baed618
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
b726fcc
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
6517118
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
6925454
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
d367b5c
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
bdd391c
Update package/MDAnalysis/core/groups.py
1ut Apr 8, 2021
e0bef58
Fix error message
1ut Apr 8, 2021
f4046e1
Merge branch 'sortdev' of https://github.com/1ut/mdanalysis into sortdev
1ut Apr 8, 2021
52b677a
separate tests
1ut Apr 8, 2021
338417e
FIx error messages
1ut Apr 8, 2021
e28530e
Merge branch 'develop' into sortdev
1ut Apr 8, 2021
170ce40
pep8
1ut Apr 8, 2021
072b159
Add example in the docs
1ut Apr 8, 2021
9ea60cd
Merge branch 'develop' into sortdev
1ut Apr 8, 2021
18d36ee
edit docs
1ut Apr 8, 2021
fbdcc6c
Merge branch 'sortdev' of https://github.com/1ut/mdanalysis into sortdev
1ut Apr 8, 2021
1e9d9e4
edit docs
1ut Apr 8, 2021
325a3d9
Update package/MDAnalysis/core/groups.py
1ut Apr 9, 2021
1de2d97
Update package/MDAnalysis/core/groups.py
1ut Apr 9, 2021
705cdd7
Update package/MDAnalysis/core/groups.py
1ut Apr 9, 2021
3377655
Unecessary \
1ut Apr 9, 2021
c2f7342
remove unnecessary .*
1ut Apr 9, 2021
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
3 changes: 2 additions & 1 deletion package/AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ Chronological list of authors
- Estefania Barreto-Ojeda
- Paarth Thadani
- Henry Kobin

- Kosuke Kudo

External code
-------------

Expand Down
4 changes: 3 additions & 1 deletion package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ The rules for this file:
lilyminium, daveminh, jbarnoud, yuxuanzhuang, VOD555, ianmkenney,
calcraven,xiki-tempula, mieczyslaw, manuel.nuno.melo, PicoCentauri,
hanatok, rmeli, aditya-kamath, tirkarthi, LeonardoBarneschi, hejamu,
biogen98, orioncohen, z3y50n, hp115, ojeda-e, thadanipaarth, HenryKobin
biogen98, orioncohen, z3y50n, hp115, ojeda-e, thadanipaarth, HenryKobin,
1ut

* 2.0.0

Expand Down Expand Up @@ -98,6 +99,7 @@ Fixes
* Fix syntax warning over comparison of literals using is (Issue #3066)

Enhancements
* Added sort method to the atomgroup (Issue #2976, PR #3188)
* ITPParser now reads [ atomtypes ] sections in ITP files, used for charges
and masses not defined in the [ atoms ] sections
* Add `set_dimensions` transformation class for setting constant
Expand Down
77 changes: 77 additions & 0 deletions package/MDAnalysis/core/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -3324,6 +3324,83 @@ def write(self, filename=None, file_format=None,

raise ValueError("No writer found for format: {}".format(filename))

def sort(self, key='ix', keyfunc=None):
"""
Returns a sorted ``AtomGroup`` using a specified attribute as the key.

Parameters
----------
key: str, optional
The name of the ``AtomGroup`` attribute to sort by (e.g. ``ids``,
``ix``. default= ``ix`` ).
keyfunc: callable, optional
A function to convert multidimensional arrays to a single
dimension. This 1D array will be used as the sort key and
is required when sorting with an ``AtomGroup`` attribute
key which has multiple dimensions. Note: this argument
is ignored when the attribute is one dimensional.

Returns
----------
:class:`AtomGroup`
Sorted ``AtomGroup``.

Example
----------

.. code-block:: python

>>> import MDAnalysis as mda
>>> from MDAnalysisTests.datafiles import PDB_small
>>> u = mda.Universe(PDB_small)
>>> ag = u.atoms[[3, 2, 1, 0]]
>>> ag.ix
array([3 2 1 0])
>>> ag = ag.sort()
>>> ag.ix
array([0 1 2 3])
>>> ag.positions
array([[-11.921, 26.307, 10.41 ],
[-11.447, 26.741, 9.595],
[-12.44 , 27.042, 10.926],
[-12.632, 25.619, 10.046]], dtype=float32)
>>> ag = ag.sort("positions", lambda x: x[:, 1])
>>> ag.positions
array([[-12.632, 25.619, 10.046],
[-11.921, 26.307, 10.41 ],
[-11.447, 26.741, 9.595],
[-12.44 , 27.042, 10.926]], dtype=float32)

Note
----------
This uses a stable sort as implemented by
`numpy.argsort(kind='stable')`.


.. versionadded:: 2.0.0
"""
idx = getattr(self.atoms, key)
if len(idx) != len(self.atoms):
raise ValueError("The array returned by the attribute '{}' "
"must have the same length as the number of "
"atoms in the input AtomGroup".format(key))
if idx.ndim == 1:
order = np.argsort(idx, kind='stable')
elif idx.ndim > 1:
if keyfunc is None:
raise NameError("The {} attribute returns a multidimensional "
"array. In order to sort it, a function "
"returning a 1D array (to be used as the sort "
"key) must be passed to the keyfunc argument"
.format(key))
sortkeys = keyfunc(idx)
if sortkeys.ndim != 1:
raise ValueError("The function assigned to the argument "
"'keyfunc':{} doesn't return a 1D array."
.format(keyfunc))
order = np.argsort(sortkeys, kind='stable')
return self.atoms[order]


class ResidueGroup(GroupBase):
"""ResidueGroup base class.
Expand Down
77 changes: 77 additions & 0 deletions testsuite/MDAnalysisTests/core/test_atomgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -1674,3 +1674,80 @@ def test_partial_timestep(self, universe):
ag.ts.velocities,
self.prec,
err_msg="Partial timestep coordinates wrong")


class TestAtomGroupSort(object):
"""Tests the AtomGroup.sort attribute"""

@pytest.fixture()
def universe(self):
u = mda.Universe.empty(
n_atoms=7,
n_residues=3,
n_segments=2,
atom_resindex=np.array([0, 0, 0, 1, 1, 1, 2]),
residue_segindex=np.array([0, 0, 1]),
trajectory=True,
velocities=True,
forces=True
)
attributes = ["id", "charge", "mass", "tempfactor"]

for i in (attributes):
u.add_TopologyAttr(i, [6, 5, 4, 3, 2, 1, 0])

u.add_TopologyAttr('resid', [2, 1, 0])
u.add_TopologyAttr('segid', [1, 0])
u.add_TopologyAttr('bonds', [(0, 1)])

return u

@pytest.fixture()
def ag(self, universe):
ag = universe.atoms
ag.positions = (-np.arange(21)).reshape(7, 3)
return ag

test_ids = [
"ix",
"ids",
"resids",
"segids",
"charges",
"masses",
"tempfactors"
]

test_data = [
("ix", np.array([0, 1, 2, 3, 4, 5, 6])),
("ids", np.array([6, 5, 4, 3, 2, 1, 0])),
("resids", np.array([6, 3, 4, 5, 0, 1, 2])),
("segids", np.array([6, 0, 1, 2, 3, 4, 5])),
("charges", np.array([6, 5, 4, 3, 2, 1, 0])),
("masses", np.array([6, 5, 4, 3, 2, 1, 0])),
("tempfactors", np.array([6, 5, 4, 3, 2, 1, 0])),
]

@pytest.mark.parametrize("inputs, expected", test_data, ids=test_ids)
def test_sort(self, ag, inputs, expected):
agsort = ag.sort(inputs)
assert np.array_equal(expected, agsort.ix)

def test_sort_bonds(self, ag):
with pytest.raises(ValueError, match=r"The array returned by the "
"attribute"):
ag.sort("bonds")

def test_sort_positions_2D(self, ag):
with pytest.raises(ValueError, match=r"The function assigned to"):
ag.sort("positions", keyfunc=lambda x: x)

def test_sort_position_no_keyfunc(self, ag):
with pytest.raises(NameError, match=r"The .* attribute returns a "
"multidimensional array. In order to sort it, "):
ag.sort("positions")

def test_sort_position(self, ag):
ref = [6, 5, 4, 3, 2, 1, 0]
agsort = ag.sort("positions", keyfunc=lambda x: x[:, 1])
assert np.array_equal(ref, agsort.ix)