Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7af3352
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Aug 7, 2019
51624f3
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Aug 9, 2019
fa7777e
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Aug 13, 2019
94ac6cc
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Aug 20, 2019
80370af
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Sep 5, 2019
36fa2ea
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Sep 10, 2019
5111103
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Oct 2, 2019
ad0c149
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Oct 3, 2019
def7c14
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Oct 16, 2019
2d693e3
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Oct 30, 2019
f7d5bc6
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Nov 21, 2019
64bcae5
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Nov 28, 2019
2e2561e
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Dec 23, 2019
2184e2b
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Jan 14, 2020
de7afcc
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Jan 16, 2020
ff4ed8d
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Jan 17, 2020
2f42b7c
add element attributes (naive)
RMeli Jan 17, 2020
7fe3c35
guess mass from names
RMeli Jan 17, 2020
8e9327f
try to get element before atom name
RMeli Jan 17, 2020
067bc8d
name change
RMeli Jan 17, 2020
ddc6be3
add test for elements attribute
RMeli Jan 17, 2020
28032cf
update docstrings
RMeli Jan 17, 2020
e00485a
Merge remote-tracking branch 'upstream/develop' into fixes/xyzelement
RMeli Jan 17, 2020
c515e89
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Jan 17, 2020
6f12ab1
test XYZ writer using elements if present
RMeli Jan 17, 2020
5c2bcbc
update docs
RMeli Jan 18, 2020
11c5bab
add versionchanged tag
RMeli Jan 18, 2020
34dc30b
update changelog
RMeli Jan 18, 2020
7d27138
Merge remote-tracking branch 'upstream/develop' into develop
RMeli Jan 18, 2020
3fca537
Merge branch 'develop' into fixes/xyzelement
RMeli Jan 18, 2020
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
4 changes: 3 additions & 1 deletion package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The rules for this file:

------------------------------------------------------------------------------
mm/dd/yy richardjgowers, kain88-de, lilyminium, p-j-smith, bdice, joaomcteixeira,
PicoCentauri, davidercruz, jbarnoud
PicoCentauri, davidercruz, jbarnoud, RMeli

* 0.21.0

Expand All @@ -35,6 +35,8 @@ Fixes
* TXYZ parser uses strings for the atom types like other parsers (Issue #2435)

Enhancements
* XYZ parser store elements attribute (#2420) and XYZ write uses the elements
attribute, if present (#2421).
* Enhanges exception message when trajectory output file has no extension assigned.
* Uniforms exception handling between Python 2.7 and Python 3: raised exceptions
do not contain previous exceptions traceback. Uses six package to handle
Expand Down
20 changes: 13 additions & 7 deletions package/MDAnalysis/coordinates/XYZ.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ class XYZWriter(base.WriterBase):

.. _xyzplugin:
http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/xyzplugin.html

.. versionchanged: 0.21.0
Use elements attribute instead of names attribute, if present
"""

format = 'XYZ'
Expand Down Expand Up @@ -149,15 +152,15 @@ def __init__(self, filename, n_atoms=None, atoms=None, convert_units=None,
self.convert_units = convert_units
else:
self.convert_units = flags['convert_lengths']
self.atomnames = self._get_atomnames(atoms)
self.atomnames = self._get_atoms_elements_or_names(atoms)
default_remark = "Written by {0} (release {1})".format(
self.__class__.__name__, __version__)
self.remark = default_remark if remark is None else remark
# can also be gz, bz2
self._xyz = util.anyopen(self.filename, 'wt')

def _get_atomnames(self, atoms):
"""Return a list of atom names"""
def _get_atoms_elements_or_names(self, atoms):
"""Return a list of atom elements (if present) or fallback to atom names"""
# Default case
if atoms is None:
return itertools.cycle(('X',))
Expand All @@ -170,9 +173,12 @@ def _get_atomnames(self, atoms):
# AtomGroup or Universe, grab the names else default
# (AtomGroup.atoms just returns AtomGroup)
try:
return atoms.atoms.names
return atoms.atoms.elements
except (AttributeError, NoDataError):
return itertools.cycle(('X',))
try:
return atoms.atoms.names
except (AttributeError, NoDataError):
return itertools.cycle(('X',))

def close(self):
"""Close the trajectory file and finalize the writing"""
Expand All @@ -184,7 +190,7 @@ def close(self):
def write(self, obj):
"""Write object `obj` at current trajectory frame to file.

Atom names in the output are taken from the `obj` or default
Atom elements (or names) in the output are taken from the `obj` or default
to the value of the `atoms` keyword supplied to the
:class:`XYZWriter` constructor.

Expand Down Expand Up @@ -218,7 +224,7 @@ def write(self, obj):
# For Universe only --- get everything
ts = obj.trajectory.ts
# update atom names
self.atomnames = self._get_atomnames(atoms)
self.atomnames = self._get_atoms_elements_or_names(atoms)

self.write_next_timestep(ts)

Expand Down
8 changes: 6 additions & 2 deletions package/MDAnalysis/topology/XYZParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
Resids,
Resnums,
Segids,
Elements,
)


Expand All @@ -69,6 +70,9 @@ class XYZParser(TopologyReaderBase):
- Masses

.. versionadded:: 0.9.1

.. versionchanged: 0.21.0
Store elements attribute, based on XYZ atom names
"""
format = 'XYZ'

Expand All @@ -92,7 +96,7 @@ def parse(self, **kwargs):

# Guessing time
atomtypes = guessers.guess_types(names)
masses = guessers.guess_masses(atomtypes)
masses = guessers.guess_masses(names)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I assume that names contain element symbols (XYZ file format). As discusses in #2420 this might not always be the case. Should I make this more flexible?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think (hope) guess_masses is smart enough to skip a bad value and print a warning?


attrs = [Atomnames(names),
Atomids(np.arange(natoms) + 1),
Expand All @@ -101,7 +105,7 @@ def parse(self, **kwargs):
Resids(np.array([1])),
Resnums(np.array([1])),
Segids(np.array(['SYSTEM'], dtype=object)),
]
Elements(names)]

top = Topology(natoms, 1, 1,
attrs=attrs)
Expand Down
15 changes: 15 additions & 0 deletions testsuite/MDAnalysisTests/coordinates/test_xyz.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,18 @@ def test_list_names(self, outfile):

u2 = mda.Universe(outfile)
assert all(u2.atoms.names == names)

@pytest.mark.parametrize("attr", ["elements", "names"])
def test_elements_and_names(self, outfile, attr):

u = mda.Universe.empty(n_atoms=5, trajectory=True)

u.add_TopologyAttr(attr, values=['Te', 'S', 'Ti', 'N', 'Ga'])

with mda.Writer(outfile) as w:
w.write(u)

with open(outfile, "r") as r:
names = ''.join(l.split()[0].strip() for l in r.readlines()[2:-1])

assert names[:-1].lower() == 'testing'
3 changes: 1 addition & 2 deletions testsuite/MDAnalysisTests/topology/test_xyz.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@ class XYZBase(ParserBase):
parser = mda.topology.XYZParser.XYZParser
expected_n_residues = 1
expected_n_segments = 1
expected_attrs = ['names']
expected_attrs = ['names', "elements"]
guessed_attrs = ['types', 'masses']


class TestXYZMini(XYZBase):
ref_filename = XYZ_mini
expected_n_atoms = 3
Expand Down