From d9bf82f8946013c818f87e1d8fd75c8b3fa334e2 Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Sat, 7 Jul 2018 01:32:58 +0100 Subject: [PATCH 01/16] added plane and axis centering transformations; added tests; updated changelogs --- package/CHANGELOG | 1 + .../MDAnalysis/transformations/__init__.py | 2 +- .../MDAnalysis/transformations/translate.py | 170 ++++++++- .../transformations/test_translate.py | 358 +++++++++++++++++- 4 files changed, 527 insertions(+), 4 deletions(-) diff --git a/package/CHANGELOG b/package/CHANGELOG index 5f99db203b0..9af06e09a10 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -19,6 +19,7 @@ The rules for this file: * 0.18.1 Enhancements + * Added box/axis/plane centering trajectory transformations * Added a box centering trajectory transformation (PR #1946) * Added a on-the-fly trajectory transformations API and a coordinate translation function (Issue #786) diff --git a/package/MDAnalysis/transformations/__init__.py b/package/MDAnalysis/transformations/__init__.py index 94444791fbf..748194c9938 100644 --- a/package/MDAnalysis/transformations/__init__.py +++ b/package/MDAnalysis/transformations/__init__.py @@ -92,7 +92,7 @@ def wrapped(ts): from __future__ import absolute_import -from .translate import translate, center_in_box +from .translate import translate, center_in_box, center_in_plane, center_in_axis diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index f3728294df3..e349df21e6e 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -33,6 +33,8 @@ from __future__ import absolute_import, division import numpy as np +from numbers import Number +from six import string_types from functools import partial from ..lib.mdamath import triclinic_vectors @@ -138,4 +140,170 @@ def wrapped(ts): return ts return wrapped - \ No newline at end of file + + +def center_in_plane(ag, plane, coordinate=0, origin=None, center='geometry', wrap=False): + """ + Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` + instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` + is centered on a plane. This plane can only be parallel to the x, y or z planes. + + Example + ------- + + .. code-block:: python + + ag = u.residues[1].atoms + ts = MDAnalysis.transformations.center_in_plane(ag,'x', 1, center='mass')(ts) + + Parameters + ---------- + ag: AtomGroup + atom group to be centered on the unit cell. + plane: str + used to define the plane on which the given AtomGroup will be centered. Defined as + a string or an array-like of the plane and the value of its translation. Suported + planes are x, y and z. + coordinate: scalar + the coordinate on which the plane is defined ( 1 for the plane x=1, for example). + Default is 0. + origin: array-like or str + coordinate on which the axes are centered. Can be an array of three coordinates or + `center` to shift the origin to the center of the unit cell. Default is `None` + which sets [0, 0, 0] as the origin of the axes. + center: str, optional + used to choose the method of centering on the given atom group. Can be 'geometry' + or 'mass' + wrap: bool, optional + If `True`, all the atoms from the given AtomGroup will be moved to the unit cell + before calculating the center of mass or geometry. Default is `False`, no changes + to the atom coordinates are done before calculating the center of the AtomGroup. + + Returns + ------- + :class:`~MDAnalysis.coordinates.base.Timestep` object + + """ + + if isinstance(plane, string_types): + if plane not in ('x', 'y', 'z'): + raise ValueError('{} is not a valid plane'.format(plane)) + if not isinstance(coordinate, Number): + raise ValueError('{} is not a valid coordinate number'.format(coordinate)) + if origin is not None: + if isinstance(origin, string_types): + if not origin == 'center': + raise ValueError('{}is not a valid origin'.format(origin)) + else: + origin = np.asarray(origin, np.float32) + if origin.shape != (3, ) and origin.shape != (1, 3): + raise ValueError('{} is not a valid origin'.format(origin)) + else: + origin = np.asarray([0, 0, 0], np.float32) + + def wrapped(ts): + boxcenter = ts.triclinic_dimensions.sum(axis=0) / 2.0 + if isinstance(origin, string_types) and origin == 'center': + _origin = boxcenter + else: + _origin = origin + if plane == 'x': + shift = _origin[0]+coordinate + position = [shift, boxcenter[1], boxcenter[2]] + if plane == 'y': + shift = _origin[1]+coordinate + position = [boxcenter[0], shift, boxcenter[2]] + if plane == 'z': + shift = _origin[2]+coordinate + position = [boxcenter[0], boxcenter[1], shift] + ts = center_in_box(ag, center=center, point=position, wrap=wrap)(ts) + + return ts + + return wrapped + + +def center_in_axis(ag, axis, origin=None, center='geometry', wrap=False): + """ + Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` + instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` + is centered on an axis. This axis can only be parallel to the x, y or z planes. + + Example + ------- + + .. code-block:: python + + ag = u.residues[1].atoms + ts = MDAnalysis.transformations.center_in_axis(ag,'x', [0,0,1], center='mass')(ts) + + Parameters + ---------- + ag: AtomGroup + atom group to be centered on the unit cell. + axis: str + used to define the plane on which the given AtomGroup will be centered. Defined as + a string or an array-like of the plane and the value of its translation. Suported + planes are x, y and z. + origin: array-like or str + coordinate on which the axes are centered. Can be an array of three coordinates or + `center` to shift the origin to the center of the unit cell. Default is `None` + which sets [0, 0, 0] as the origin of the axis. + center: str, optional + used to choose the method of centering on the given atom group. Can be 'geometry' + or 'mass' + wrap: bool, optional + If `True`, all the atoms from the given AtomGroup will be moved to the unit cell + before calculating the center of mass or geometry. Default is `False`, no changes + to the atom coordinates are done before calculating the center of the AtomGroup. + + Returns + ------- + :class:`~MDAnalysis.coordinates.base.Timestep` object + + """ + pbc_arg = wrap + if isinstance(axis, string_types): + if axis not in ('x', 'y', 'z'): + raise ValueError('{} is not a valid axis'.format(axis)) + if origin is not None: + if isinstance(origin, string_types): + if not origin == 'center': + raise ValueError('{}is not a valid origin'.format(origin)) + else: + origin = np.asarray(origin, np.float32) + if origin.shape != (3, ) and origin.shape != (1, 3): + raise ValueError('{} is not a valid origin'.format(origin)) + else: + origin = np.asarray([0, 0, 0], np.float32) + try: + if center == 'geometry': + center_method = partial(ag.center_of_geometry, pbc=pbc_arg) + elif center == 'mass': + center_method = partial(ag.center_of_mass, pbc=pbc_arg) + else: + raise ValueError('{} is not a valid argument for center'.format(center)) + except AttributeError: + if center == 'mass': + raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) + else: + raise ValueError('{} is not an AtomGroup object'.format(ag)) + + def wrapped(ts): + if isinstance(origin, string_types) and origin == 'center': + _origin = ts.triclinic_dimensions.sum(axis=0) / 2.0 + else: + _origin = origin + ag_center = center_method() + if axis == 'x': + center = np.asarray([ag_center[0], _origin[1], _origin[2]], np.float32) + if axis == 'y': + center = np.asarray([_origin[0], ag_center[1], _origin[2]], np.float32) + if axis == 'z': + center = np.asarray([_origin[0], _origin[1], ag_center[2]], np.float32) + vector = center - ag_center + ts.positions += vector + + return ts + + return wrapped diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 6ae8b8a39e4..2b646ecf2cd 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -27,7 +27,7 @@ from numpy.testing import assert_array_almost_equal import MDAnalysis as mda -from MDAnalysis.transformations import translate, center_in_box +from MDAnalysis.transformations import translate, center_in_box, center_in_plane, center_in_axis from MDAnalysisTests import make_Universe @@ -196,8 +196,335 @@ def test_center_in_box_coords_all_options(translate_universes): trans = center_in_box(ag, center='mass', wrap=True, point=newpoint)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) +def test_center_in_axis_bad_ag(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + # what happens if something other than an AtomGroup is given? + bad_ag = 1 + axis = 'x' + with pytest.raises(ValueError): + center_in_axis(bad_ag, axis)(ts) + + +@pytest.mark.parametrize('origin', ( + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), + np.array([[0], [1], [2]])) +) +def test_center_in_axis_bad_origin(translate_universes, origin): + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # what if the box is in the wrong format? + axis = 'x' + with pytest.raises(ValueError): + center_in_axis(ag, axis, origin=origin)(ts) + + +def test_center_in_axis_bad_pbc(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # is pbc passed to the center methods? + # if yes it should raise an exception for boxes that are zero in size + axis = 'x' + with pytest.raises(ValueError): + center_in_axis(ag,axis, wrap=True)(ts) + + +def test_center_in_axis_bad_center(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # what if a wrong center type name is passed? + bad_center = " " + axis = 'x' + with pytest.raises(ValueError): + center_in_axis(ag, axis, center=bad_center)(ts) + + +def test_center_in_axis_no_masses(translate_universes): + # this universe has no masses + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # if the universe has no masses and `mass` is passed as the center arg + bad_center = "mass" + axis = 'x' + with pytest.raises(AttributeError): + center_in_axis(ag, axis, center=bad_center)(ts) + + +def test_center_in_axis_coords_no_options(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ref_center = np.float32([6, 7, 8]) + axis = 'x' + axis_point = np.float32([ref_center[0], 0, 0]) + ref.positions += axis_point - ref_center + ag = trans_u.residues[0].atoms + trans = center_in_axis(ag, axis)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_axis_coords_with_pbc(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue + # taking pbc into account for center of geometry calculation? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + trans_u.dimensions = [363., 364., 365., 90., 90., 90.] + ag = trans_u.residues[24].atoms + ref_center = ag.center_of_geometry(pbc=True) + axis = 'x' + axis_point = np.float32([ref_center[0], 0, 0]) + ref.positions += axis_point - ref_center + trans = center_in_axis(ag, axis, wrap=True)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_axis_coords_with_mass(translate_universes): + # using masses for calculating the center of the atomgroup + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[24].atoms + ref_center = ag.center_of_mass() + axis = 'x' + axis_point = np.float32([ref_center[0], 0, 0]) + ref.positions += axis_point - ref_center + trans = center_in_axis(ag, axis, center="mass")(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_axis_coords_with_coord_origin(translate_universes): + # what happens when we use a custom coordinate as origin point? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[0].atoms + origin = [1000, 1000, 1000] + ref_center = np.float32([6, 7, 8]) + axis = 'x' + axis_point = np.float32([ref_center[0], origin[1], origin[2]]) + ref.positions += axis_point - ref_center + trans = center_in_axis(ag, axis, origin=origin)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_axis_coords_with_center_origin(translate_universes): + # what happens when we use the center of the unit cell as origin point? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[0].atoms + box_center = np.float32([186., 186.5, 187.]) + origin = box_center + ref_center = np.float32([6, 7, 8]) + axis = 'x' + axis_point = np.float32([ref_center[0], origin[1], origin[2]]) + ref.positions += axis_point - ref_center + trans = center_in_axis(ag, axis, origin='center')(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_axis_coords_all_options(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[24].atoms + neworigin = [1000, 1000, 1000] + ref_center = ag.center_of_mass(pbc=True) + axis = 'x' + axis_point = np.float32([ref_center[0], neworigin[1], neworigin[2]]) + ref.positions += axis_point - ref_center + trans = center_in_axis(ag, axis, center='mass', wrap=True, origin=neworigin)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_plane_bad_ag(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + # what happens if something other than an AtomGroup is given? + bad_ag = 1 + plane = 'x' + with pytest.raises(ValueError): + center_in_plane(bad_ag, plane)(ts) + + +@pytest.mark.parametrize('origin', ( + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), + np.array([[0], [1], [2]])) +) +def test_center_in_plane_bad_origin(translate_universes, origin): + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # what if the box is in the wrong format? + plane = 'x' + with pytest.raises(ValueError): + center_in_plane(ag, plane, origin=origin)(ts) + + +@pytest.mark.parametrize('coordinate', ( + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), + np.array([[0], [1], [2]])) +) +def test_center_in_plane_bad_coordinate(translate_universes, coordinate): + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # what if the box is in the wrong format? + plane = 'x' + with pytest.raises(ValueError): + center_in_plane(ag, plane, coordinate=coordinate)(ts) + + +def test_center_in_plane_bad_pbc(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # is pbc passed to the center methods? + # if yes it should raise an exception for boxes that are zero in size + plane = 'x' + with pytest.raises(ValueError): + center_in_plane(ag, plane, wrap=True)(ts) + + +def test_center_in_plane_bad_center(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # what if a wrong center type name is passed? + bad_center = " " + plane = 'x' + with pytest.raises(ValueError): + center_in_plane(ag, plane, center=bad_center)(ts) + + +def test_center_in_planes_no_masses(translate_universes): + # this universe has no masses + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # if the universe has no masses and `mass` is passed as the center arg + bad_center = "mass" + plane = 'x' + with pytest.raises(AttributeError): + center_in_plane(ag, plane, center=bad_center)(ts) + + +def test_center_in_plane_coords_no_options(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ref_center = np.float32([6, 7, 8]) + box_center = np.float32([186., 186.5, 187.]) + plane = 'x' + plane_point = np.float32([0, box_center[1], box_center[2]]) + ref.positions += plane_point - ref_center + ag = trans_u.residues[0].atoms + trans = center_in_plane(ag, plane)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_plane_coords_with_coordinate(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ref_center = np.float32([6, 7, 8]) + box_center = np.float32([186., 186.5, 187.]) + coordinate = 10 + plane = 'x' + plane_point = np.float32([coordinate, box_center[1], box_center[2]]) + ref.positions += plane_point - ref_center + ag = trans_u.residues[0].atoms + trans = center_in_plane(ag, plane, coordinate=coordinate)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_plane_coords_with_pbc(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + trans_u.dimensions = [363., 364., 365., 90., 90., 90.] + box_center = np.float32([181.5, 182., 182.5]) + ag = trans_u.residues[24].atoms + ref_center = ag.center_of_geometry(pbc=True) + plane = 'x' + plane_point = np.float32([0, box_center[1], box_center[2]]) + ref.positions += plane_point - ref_center + trans = center_in_plane(ag, plane, wrap=True)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_plane_coords_with_mass(translate_universes): + # using masses for calculating the center of the atomgroup + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[24].atoms + box_center = np.float32([186., 186.5, 187.]) + ref_center = ag.center_of_mass() + plane = 'x' + plane_point = np.float32([0, box_center[1], box_center[2]]) + ref.positions += plane_point - ref_center + trans = center_in_plane(ag, plane, center="mass")(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_plane_coords_with_coord_origin(translate_universes): + # what happens when we use a custom coordinate as origin point? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[0].atoms + origin = [1000, 1000, 1000] + box_center = np.float32([186., 186.5, 187.]) + ref_center = np.float32([6, 7, 8]) + plane = 'x' + plane_point = np.float32([origin[0], box_center[1], box_center[2]]) + ref.positions += plane_point - ref_center + trans = center_in_plane(ag, plane, origin=origin)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_plane_coords_with_center_origin(translate_universes): + # what happens when we use the center of the unit cell as origin point? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[0].atoms + box_center = np.float32([186., 186.5, 187.]) + ref_center = np.float32([6, 7, 8]) + plane = 'x' + plane_point = box_center + ref.positions += plane_point - ref_center + trans = center_in_plane(ag, plane, origin='center')(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + -def test_center_transformations_api(translate_universes): +def test_center_in_plane_coords_all_options(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ag = trans_u.residues[24].atoms + trans_u.dimensions = [363., 364., 365., 90., 90., 90.] + box_center = np.float32([181.5, 182., 182.5]) + neworigin = [1000, 1000, 1000] + coordinate = 100 + ref_center = ag.center_of_mass(pbc=True) + plane = 'x' + plane_point = np.float32([neworigin[0]+coordinate, box_center[1], box_center[2]]) + ref.positions += plane_point - ref_center + trans = center_in_plane(ag, plane, coordinate=coordinate, origin=neworigin, center='mass', wrap=True)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + +def test_center_in_box_transformations_api(translate_universes): # test if the translate transformation works when using the # on-the-fly transformations API ref_u, trans_u = translate_universes @@ -208,3 +535,30 @@ def test_center_transformations_api(translate_universes): ag = trans_u.residues[0].atoms trans_u.trajectory.add_transformations(center_in_box(ag)) assert_array_almost_equal(trans_u.trajectory.ts.positions, ref.positions, decimal=6) + + +def test_center_in_axis_transformations_api(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ref_center = np.float32([6, 7, 8]) + axis = 'x' + axis_point = np.float32([ref_center[0], 0, 0]) + ref.positions += axis_point - ref_center + ag = trans_u.residues[0].atoms + trans_u.trajectory.add_transformations(center_in_axis(ag, axis)) + assert_array_almost_equal(trans_u.trajectory.ts.positions, ref.positions, decimal=6) + + +def test_center_in_plane_transformations_api(translate_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + ref_u, trans_u = translate_universes + ref = ref_u.trajectory.ts + ref_center = np.float32([6, 7, 8]) + box_center = np.float32([186., 186.5, 187.]) + plane = 'x' + plane_point = np.float32([0, box_center[1], box_center[2]]) + ref.positions += plane_point - ref_center + ag = trans_u.residues[0].atoms + trans_u.trajectory.add_transformations(center_in_plane(ag, plane)) + assert_array_almost_equal(trans_u.trajectory.ts.positions, ref.positions, decimal=6) From e066f17bc8b63a89ca6d59a754d5c18d03715763 Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Wed, 11 Jul 2018 16:14:59 +0100 Subject: [PATCH 02/16] better docs; all checks and calculations are done in center_in_plane --- .../MDAnalysis/transformations/translate.py | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index e349df21e6e..9b95655d7ce 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -46,7 +46,13 @@ def translate(vector): Example ------- - ts = MDAnalysis.transformations.translate([1,2,3])(ts) + + Translate the coordinates of the system by the [1, 2, 3] vector + + ..code-block:: python + + transform = MDAnalysis.transformations.translate([1,2,3]) + u.trajectory.add_transformations(transform) Parameters ---------- @@ -55,7 +61,7 @@ def translate(vector): Returns ------- - :class:`~MDAnalysis.coordinates.base.Timestep` object + `~MDAnalysis.coordinates.base.Timestep` """ if len(vector)>2: @@ -81,10 +87,14 @@ def center_in_box(ag, center='geometry', point=None, wrap=False): Example ------- + Translate the center of mass of of the second residue of the universe u to the center of the unit + cell: + .. code-block:: python ag = u.residues[1].atoms - ts = MDAnalysis.transformations.center(ag,center='mass')(ts) + transform = MDAnalysis.transformations.center(ag,center='mass') + u.trajectory.add_transformations(transform) Parameters ---------- @@ -104,7 +114,7 @@ def center_in_box(ag, center='geometry', point=None, wrap=False): Returns ------- - :class:`~MDAnalysis.coordinates.base.Timestep` object + `~MDAnalysis.coordinates.base.Timestep` """ @@ -142,7 +152,7 @@ def wrapped(ts): return wrapped -def center_in_plane(ag, plane, coordinate=0, origin=None, center='geometry', wrap=False): +def center_in_plane(ag, plane, coordinate=0, origin=[0,0,0], center='geometry', wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -151,10 +161,13 @@ def center_in_plane(ag, plane, coordinate=0, origin=None, center='geometry', wra Example ------- + Translate the center of mass of the second residue of the universe u to the center of the x=1 plane: + .. code-block:: python ag = u.residues[1].atoms - ts = MDAnalysis.transformations.center_in_plane(ag,'x', 1, center='mass')(ts) + transform = MDAnalysis.transformations.center_in_plane(ag,'x', 1, center='mass') + u.trajectory.add_transformations(transform) Parameters ---------- @@ -181,11 +194,12 @@ def center_in_plane(ag, plane, coordinate=0, origin=None, center='geometry', wra Returns ------- - :class:`~MDAnalysis.coordinates.base.Timestep` object + `~MDAnalysis.coordinates.base.Timestep` """ - if isinstance(plane, string_types): + pbc_arg = wrap + if plane is not None: if plane not in ('x', 'y', 'z'): raise ValueError('{} is not a valid plane'.format(plane)) if not isinstance(coordinate, Number): @@ -198,9 +212,18 @@ def center_in_plane(ag, plane, coordinate=0, origin=None, center='geometry', wra origin = np.asarray(origin, np.float32) if origin.shape != (3, ) and origin.shape != (1, 3): raise ValueError('{} is not a valid origin'.format(origin)) - else: - origin = np.asarray([0, 0, 0], np.float32) - + try: + if center == 'geometry': + center_method = partial(ag.center_of_geometry, pbc=pbc_arg) + elif center == 'mass': + center_method = partial(ag.center_of_mass, pbc=pbc_arg) + else: + raise ValueError('{} is not a valid argument for center'.format(center)) + except AttributeError: + if center == 'mass': + raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) + else: + raise ValueError('{} is not an AtomGroup object'.format(ag)) def wrapped(ts): boxcenter = ts.triclinic_dimensions.sum(axis=0) / 2.0 if isinstance(origin, string_types) and origin == 'center': @@ -216,14 +239,15 @@ def wrapped(ts): if plane == 'z': shift = _origin[2]+coordinate position = [boxcenter[0], boxcenter[1], shift] - ts = center_in_box(ag, center=center, point=position, wrap=wrap)(ts) + vector = np.asarray(position, np.float32) - center_method() + ts.positions += vector return ts return wrapped -def center_in_axis(ag, axis, origin=None, center='geometry', wrap=False): +def center_in_axis(ag, axis, origin=[0,0,0], center='geometry', wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -263,7 +287,7 @@ def center_in_axis(ag, axis, origin=None, center='geometry', wrap=False): """ pbc_arg = wrap - if isinstance(axis, string_types): + if axis is not None: if axis not in ('x', 'y', 'z'): raise ValueError('{} is not a valid axis'.format(axis)) if origin is not None: From 149cf239b9b756dfb0827472921c6a9f59ff27b1 Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Wed, 11 Jul 2018 22:45:44 +0100 Subject: [PATCH 03/16] dtype of coordinates is now tested; better docs; updated changelog --- package/CHANGELOG | 3 +- .../MDAnalysis/transformations/translate.py | 14 +++++--- .../transformations/test_translate.py | 36 +++++++++++++++++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/package/CHANGELOG b/package/CHANGELOG index 43efc173cc9..a896c638bc9 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -19,9 +19,8 @@ The rules for this file: * 0.18.1 Enhancements - * Added box/axis/plane centering trajectory transformations * Added a rotation coordinate transformation (PR #1937) - * Added a box centering trajectory transformation (PR #1946) + * Added a box, plane and axis centering trajectory transformations (PR #1946 and #1973) * Added a on-the-fly trajectory transformations API and a coordinate translation function (Issue #786) * Added various duecredit stubs diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 9b95655d7ce..42c37de9dbb 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -61,7 +61,7 @@ def translate(vector): Returns ------- - `~MDAnalysis.coordinates.base.Timestep` + MDAnalysis.coordinates.base.Timestep """ if len(vector)>2: @@ -114,7 +114,7 @@ def center_in_box(ag, center='geometry', point=None, wrap=False): Returns ------- - `~MDAnalysis.coordinates.base.Timestep` + MDAnalysis.coordinates.base.Timestep """ @@ -194,7 +194,7 @@ def center_in_plane(ag, plane, coordinate=0, origin=[0,0,0], center='geometry', Returns ------- - `~MDAnalysis.coordinates.base.Timestep` + MDAnalysis.coordinates.base.Timestep """ @@ -256,10 +256,14 @@ def center_in_axis(ag, axis, origin=[0,0,0], center='geometry', wrap=False): Example ------- + Translate the center of mass of of the second residue of the universe u to the center of the line + parallel to the x axis that passes through the [0, 0, 1] point: + .. code-block:: python ag = u.residues[1].atoms - ts = MDAnalysis.transformations.center_in_axis(ag,'x', [0,0,1], center='mass')(ts) + transform = MDAnalysis.transformations.center_in_axis(ag,'x', [0,0,1], center='mass') + u.trajectory.add_transformation(transform) Parameters ---------- @@ -283,7 +287,7 @@ def center_in_axis(ag, axis, origin=[0,0,0], center='geometry', wrap=False): Returns ------- - :class:`~MDAnalysis.coordinates.base.Timestep` object + MDAnalysis.coordinates.base.Timestep """ pbc_arg = wrap diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 2b646ecf2cd..68600c1f4fa 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -65,7 +65,15 @@ def test_translate_vector(translate_universes, vector): with pytest.raises(ValueError): translate(vector)(ts) - + +def test_translate_coords_dtype(translate_universes): + # is the dtype of the coordinates correct? + trans_u = translate_universes[1] + vector = np.float32([1, 2, 3]) + trans = translate(vector)(trans_u.trajectory.ts) + assert(trans.positions.dtype == np.float32) + + def test_translate_transformations_api(translate_universes): # test if the translate transformation works when using the # on-the-fly transformations API @@ -132,6 +140,14 @@ def test_center_in_box_no_masses(translate_universes): center_in_box(ag, center=bad_center)(ts) +def test_center_in_box_coords_dtype(translate_universes): + # is the dtype of the coordinates correct? + trans_u = translate_universes[1] + ag = trans_u.residues[0].atoms + trans = center_in_box(ag)(trans_u.trajectory.ts) + assert(trans.positions.dtype == np.float32) + + def test_center_in_box_coords_no_options(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? ref_u, trans_u = translate_universes @@ -255,6 +271,14 @@ def test_center_in_axis_no_masses(translate_universes): with pytest.raises(AttributeError): center_in_axis(ag, axis, center=bad_center)(ts) +def test_center_in_axis_coords_dtype(translate_universes): + # is the dtype of the coordinates correct? + trans_u = translate_universes[1] + axis = 'x' + ag = trans_u.residues[0].atoms + trans = center_in_axis(ag, axis)(trans_u.trajectory.ts) + assert(trans.positions.dtype == np.float32) + def test_center_in_axis_coords_no_options(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? @@ -417,7 +441,15 @@ def test_center_in_planes_no_masses(translate_universes): with pytest.raises(AttributeError): center_in_plane(ag, plane, center=bad_center)(ts) - +def test_center_in_plane_coords_dtype(translate_universes): + # is the dtype of the coordinates correct? + trans_u = translate_universes[1] + plane = 'x' + ag = trans_u.residues[0].atoms + trans = center_in_plane(ag, plane)(trans_u.trajectory.ts) + assert(trans.positions.dtype == np.float32) + + def test_center_in_plane_coords_no_options(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? ref_u, trans_u = translate_universes From c8a9f84614562da82670865bccfa51fb0df3d5c4 Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Fri, 13 Jul 2018 17:21:55 +0100 Subject: [PATCH 04/16] center_in_axis/plane now use the center of the unit cell as default ; changed some options names to something clearer; updated tests --- .../MDAnalysis/transformations/translate.py | 123 ++++++------- .../transformations/test_translate.py | 169 ++++++++---------- 2 files changed, 136 insertions(+), 156 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 42c37de9dbb..f106a83613b 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -77,7 +77,7 @@ def wrapped(ts): return wrapped -def center_in_box(ag, center='geometry', point=None, wrap=False): +def center_in_box(ag, center_of='geometry', point=None, wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -93,14 +93,14 @@ def center_in_box(ag, center='geometry', point=None, wrap=False): .. code-block:: python ag = u.residues[1].atoms - transform = MDAnalysis.transformations.center(ag,center='mass') + transform = MDAnalysis.transformations.center(ag, center_of='mass') u.trajectory.add_transformations(transform) Parameters ---------- ag: AtomGroup atom group to be centered on the unit cell. - center: str, optional + center_of: str, optional used to choose the method of centering on the given atom group. Can be 'geometry' or 'mass' point: array-like, optional @@ -124,14 +124,14 @@ def center_in_box(ag, center='geometry', point=None, wrap=False): if point.shape != (3, ) and point.shape != (1, 3): raise ValueError('{} is not a valid point'.format(point)) try: - if center == 'geometry': + if center_of == 'geometry': center_method = partial(ag.center_of_geometry, pbc=pbc_arg) - elif center == 'mass': + elif center_of == 'mass': center_method = partial(ag.center_of_mass, pbc=pbc_arg) else: - raise ValueError('{} is not a valid argument for center'.format(center)) + raise ValueError('{} is not a valid argument for "center_of"'.format(center_of)) except AttributeError: - if center == 'mass': + if center_of == 'mass': raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) else: raise ValueError('{} is not an AtomGroup object'.format(ag)) @@ -152,21 +152,22 @@ def wrapped(ts): return wrapped -def center_in_plane(ag, plane, coordinate=0, origin=[0,0,0], center='geometry', wrap=False): +def center_in_plane(ag, plane, d=0, center_from="center", center_of='geometry', wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` - is centered on a plane. This plane can only be parallel to the x, y or z planes. + is centered on a plane. This plane can only be parallel to the yz, xz or xy planes. Example ------- - Translate the center of mass of the second residue of the universe u to the center of the x=1 plane: + Translate the center of mass of the second residue of the universe u to the center of the + x=1 plane: .. code-block:: python ag = u.residues[1].atoms - transform = MDAnalysis.transformations.center_in_plane(ag,'x', 1, center='mass') + transform = MDAnalysis.transformations.center_in_plane(ag, yz, 1, center_of='mass') u.trajectory.add_transformations(transform) Parameters @@ -176,15 +177,16 @@ def center_in_plane(ag, plane, coordinate=0, origin=[0,0,0], center='geometry', plane: str used to define the plane on which the given AtomGroup will be centered. Defined as a string or an array-like of the plane and the value of its translation. Suported - planes are x, y and z. - coordinate: scalar - the coordinate on which the plane is defined ( 1 for the plane x=1, for example). - Default is 0. - origin: array-like or str - coordinate on which the axes are centered. Can be an array of three coordinates or - `center` to shift the origin to the center of the unit cell. Default is `None` - which sets [0, 0, 0] as the origin of the axes. - center: str, optional + planes are yz, xz and xy planes. + d: scalar + point where the plane crosses its perpendicular axis. This value is the constant d + on the general plane equation ax + by + cz +d = 0 for the yz, xz and xy planes. + Default is 0 (zero). + center_from: array-like or str + coordinate from which the axes are centered. Can be an array of three coordinate + values or `center` which centers the AtomGroup coordinates on the center of the + unit cell. Default is `center`. + center_of: str, optional used to choose the method of centering on the given atom group. Can be 'geometry' or 'mass' wrap: bool, optional @@ -200,44 +202,45 @@ def center_in_plane(ag, plane, coordinate=0, origin=[0,0,0], center='geometry', pbc_arg = wrap if plane is not None: - if plane not in ('x', 'y', 'z'): + if plane not in ('xy', 'yz', 'xz'): raise ValueError('{} is not a valid plane'.format(plane)) - if not isinstance(coordinate, Number): - raise ValueError('{} is not a valid coordinate number'.format(coordinate)) - if origin is not None: - if isinstance(origin, string_types): - if not origin == 'center': - raise ValueError('{}is not a valid origin'.format(origin)) + if not isinstance(d, Number): + raise ValueError('{} is not a valid value for d'.format(d)) + if center_from is not None: + if isinstance(center_from, string_types): + if not center_from == 'center': + raise ValueError('{} is not a valid "center_from"'.format(center_from)) else: - origin = np.asarray(origin, np.float32) - if origin.shape != (3, ) and origin.shape != (1, 3): - raise ValueError('{} is not a valid origin'.format(origin)) + center_from = np.asarray(center_from, np.float32) + if center_from.shape != (3, ) and center_from.shape != (1, 3): + raise ValueError('{} is not a valid "center_from"'.format(center_from)) try: - if center == 'geometry': + if center_of == 'geometry': center_method = partial(ag.center_of_geometry, pbc=pbc_arg) - elif center == 'mass': + elif center_of == 'mass': center_method = partial(ag.center_of_mass, pbc=pbc_arg) else: - raise ValueError('{} is not a valid argument for center'.format(center)) + raise ValueError('{} is not a valid argument for "center_of"'.format(center_of)) except AttributeError: - if center == 'mass': + if center_of == 'mass': raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) else: raise ValueError('{} is not an AtomGroup object'.format(ag)) + def wrapped(ts): boxcenter = ts.triclinic_dimensions.sum(axis=0) / 2.0 - if isinstance(origin, string_types) and origin == 'center': + if isinstance(center_from, string_types) and center_from == 'center': _origin = boxcenter else: - _origin = origin - if plane == 'x': - shift = _origin[0]+coordinate + _origin = center_from + if plane == 'yz': + shift = _origin[0]+d position = [shift, boxcenter[1], boxcenter[2]] - if plane == 'y': - shift = _origin[1]+coordinate + if plane == 'xz': + shift = _origin[1]+d position = [boxcenter[0], shift, boxcenter[2]] - if plane == 'z': - shift = _origin[2]+coordinate + if plane == 'xy': + shift = _origin[2]+d position = [boxcenter[0], boxcenter[1], shift] vector = np.asarray(position, np.float32) - center_method() ts.positions += vector @@ -247,7 +250,7 @@ def wrapped(ts): return wrapped -def center_in_axis(ag, axis, origin=[0,0,0], center='geometry', wrap=False): +def center_in_axis(ag, axis, center_from="center", center_of='geometry', wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -262,7 +265,7 @@ def center_in_axis(ag, axis, origin=[0,0,0], center='geometry', wrap=False): .. code-block:: python ag = u.residues[1].atoms - transform = MDAnalysis.transformations.center_in_axis(ag,'x', [0,0,1], center='mass') + transform = MDAnalysis.transformations.center_in_axis(ag, 'x', [0,0,1], center_of='mass') u.trajectory.add_transformation(transform) Parameters @@ -273,11 +276,11 @@ def center_in_axis(ag, axis, origin=[0,0,0], center='geometry', wrap=False): used to define the plane on which the given AtomGroup will be centered. Defined as a string or an array-like of the plane and the value of its translation. Suported planes are x, y and z. - origin: array-like or str + center_from: array-like or str coordinate on which the axes are centered. Can be an array of three coordinates or `center` to shift the origin to the center of the unit cell. Default is `None` which sets [0, 0, 0] as the origin of the axis. - center: str, optional + center_of: str, optional used to choose the method of centering on the given atom group. Can be 'geometry' or 'mass' wrap: bool, optional @@ -294,34 +297,32 @@ def center_in_axis(ag, axis, origin=[0,0,0], center='geometry', wrap=False): if axis is not None: if axis not in ('x', 'y', 'z'): raise ValueError('{} is not a valid axis'.format(axis)) - if origin is not None: - if isinstance(origin, string_types): - if not origin == 'center': - raise ValueError('{}is not a valid origin'.format(origin)) + if center_from is not None: + if isinstance(center_from, string_types): + if not center_from == 'center': + raise ValueError('{} is not a valid "center_from"'.format(center_from)) else: - origin = np.asarray(origin, np.float32) - if origin.shape != (3, ) and origin.shape != (1, 3): - raise ValueError('{} is not a valid origin'.format(origin)) - else: - origin = np.asarray([0, 0, 0], np.float32) + center_from = np.asarray(center_from, np.float32) + if center_from.shape != (3, ) and center_from.shape != (1, 3): + raise ValueError('{} is not a valid "center_from"'.format(center_from)) try: - if center == 'geometry': + if center_of == 'geometry': center_method = partial(ag.center_of_geometry, pbc=pbc_arg) - elif center == 'mass': + elif center_of == 'mass': center_method = partial(ag.center_of_mass, pbc=pbc_arg) else: - raise ValueError('{} is not a valid argument for center'.format(center)) + raise ValueError('{} is not a valid argument for "center_of"'.format(center_of)) except AttributeError: - if center == 'mass': + if center_of == 'mass': raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) else: raise ValueError('{} is not an AtomGroup object'.format(ag)) def wrapped(ts): - if isinstance(origin, string_types) and origin == 'center': + if isinstance(center_from, string_types) and center_from == 'center': _origin = ts.triclinic_dimensions.sum(axis=0) / 2.0 else: - _origin = origin + _origin = center_from ag_center = center_method() if axis == 'x': center = np.asarray([ag_center[0], _origin[1], _origin[2]], np.float32) diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 68600c1f4fa..60131068d5b 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -127,7 +127,7 @@ def test_center_in_box_bad_center(translate_universes): # what if a wrong center type name is passed? bad_center = " " with pytest.raises(ValueError): - center_in_box(ag, center=bad_center)(ts) + center_in_box(ag, center_of=bad_center)(ts) def test_center_in_box_no_masses(translate_universes): @@ -137,7 +137,7 @@ def test_center_in_box_no_masses(translate_universes): # if the universe has no masses and `mass` is passed as the center arg bad_center = "mass" with pytest.raises(AttributeError): - center_in_box(ag, center=bad_center)(ts) + center_in_box(ag, center_of=bad_center)(ts) def test_center_in_box_coords_dtype(translate_universes): @@ -182,7 +182,7 @@ def test_center_in_box_coords_with_mass(translate_universes): box_center = np.float32([186., 186.5, 187.]) ref_center = ag.center_of_mass() ref.positions += box_center - ref_center - trans = center_in_box(ag, center="mass")(trans_u.trajectory.ts) + trans = center_in_box(ag, center_of="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -209,7 +209,7 @@ def test_center_in_box_coords_all_options(translate_universes): box_center = np.float32(newpoint) ref_center = ag.center_of_mass(pbc=True) ref.positions += box_center - ref_center - trans = center_in_box(ag, center='mass', wrap=True, point=newpoint)(trans_u.trajectory.ts) + trans = center_in_box(ag, center_of='mass', wrap=True, point=newpoint)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) def test_center_in_axis_bad_ag(translate_universes): @@ -222,7 +222,7 @@ def test_center_in_axis_bad_ag(translate_universes): center_in_axis(bad_ag, axis)(ts) -@pytest.mark.parametrize('origin', ( +@pytest.mark.parametrize('center_from', ( [0, 1], [0, 1, 2, 3, 4], np.array([0, 1]), @@ -230,13 +230,13 @@ def test_center_in_axis_bad_ag(translate_universes): np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]])) ) -def test_center_in_axis_bad_origin(translate_universes, origin): +def test_center_in_axis_bad_center_from(translate_universes, center_from): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if the box is in the wrong format? axis = 'x' with pytest.raises(ValueError): - center_in_axis(ag, axis, origin=origin)(ts) + center_in_axis(ag, axis, center_from=center_from)(ts) def test_center_in_axis_bad_pbc(translate_universes): @@ -250,7 +250,7 @@ def test_center_in_axis_bad_pbc(translate_universes): center_in_axis(ag,axis, wrap=True)(ts) -def test_center_in_axis_bad_center(translate_universes): +def test_center_in_axis_bad_center_of(translate_universes): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms @@ -258,7 +258,7 @@ def test_center_in_axis_bad_center(translate_universes): bad_center = " " axis = 'x' with pytest.raises(ValueError): - center_in_axis(ag, axis, center=bad_center)(ts) + center_in_axis(ag, axis, center_of=bad_center)(ts) def test_center_in_axis_no_masses(translate_universes): @@ -269,7 +269,7 @@ def test_center_in_axis_no_masses(translate_universes): bad_center = "mass" axis = 'x' with pytest.raises(AttributeError): - center_in_axis(ag, axis, center=bad_center)(ts) + center_in_axis(ag, axis, center_of=bad_center)(ts) def test_center_in_axis_coords_dtype(translate_universes): # is the dtype of the coordinates correct? @@ -281,14 +281,16 @@ def test_center_in_axis_coords_dtype(translate_universes): def test_center_in_axis_coords_no_options(translate_universes): - # what happens when we center the coordinates arround the center of geometry of a residue? + # what happens when we center the coordinates on an axis without any other options? ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts + ag = trans_u.residues[0].atoms + box_center = np.float32([186., 186.5, 187.]) + center_from = box_center ref_center = np.float32([6, 7, 8]) axis = 'x' - axis_point = np.float32([ref_center[0], 0, 0]) + axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) ref.positions += axis_point - ref_center - ag = trans_u.residues[0].atoms trans = center_in_axis(ag, axis)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -300,9 +302,11 @@ def test_center_in_axis_coords_with_pbc(translate_universes): ref = ref_u.trajectory.ts trans_u.dimensions = [363., 364., 365., 90., 90., 90.] ag = trans_u.residues[24].atoms + box_center = np.float32([181.5, 182., 182.5]) + center_from = box_center ref_center = ag.center_of_geometry(pbc=True) axis = 'x' - axis_point = np.float32([ref_center[0], 0, 0]) + axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) ref.positions += axis_point - ref_center trans = center_in_axis(ag, axis, wrap=True)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -314,39 +318,26 @@ def test_center_in_axis_coords_with_mass(translate_universes): ref = ref_u.trajectory.ts ag = trans_u.residues[24].atoms ref_center = ag.center_of_mass() + box_center = np.float32([186., 186.5, 187.]) + center_from = box_center axis = 'x' - axis_point = np.float32([ref_center[0], 0, 0]) + axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, center="mass")(trans_u.trajectory.ts) + trans = center_in_axis(ag, axis, center_of="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_axis_coords_with_coord_origin(translate_universes): - # what happens when we use a custom coordinate as origin point? - ref_u, trans_u = translate_universes - ref = ref_u.trajectory.ts - ag = trans_u.residues[0].atoms - origin = [1000, 1000, 1000] - ref_center = np.float32([6, 7, 8]) - axis = 'x' - axis_point = np.float32([ref_center[0], origin[1], origin[2]]) - ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, origin=origin)(trans_u.trajectory.ts) - assert_array_almost_equal(trans.positions, ref.positions, decimal=6) - - -def test_center_in_axis_coords_with_center_origin(translate_universes): - # what happens when we use the center of the unit cell as origin point? +def test_center_in_axis_coords_with_coord_center_from(translate_universes): + # what happens when we use a custom coordinate as center_from point? ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[0].atoms - box_center = np.float32([186., 186.5, 187.]) - origin = box_center + center_from = [1000, 1000, 1000] ref_center = np.float32([6, 7, 8]) axis = 'x' - axis_point = np.float32([ref_center[0], origin[1], origin[2]]) + axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, origin='center')(trans_u.trajectory.ts) + trans = center_in_axis(ag, axis, center_from=center_from)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -361,7 +352,7 @@ def test_center_in_axis_coords_all_options(translate_universes): axis = 'x' axis_point = np.float32([ref_center[0], neworigin[1], neworigin[2]]) ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, center='mass', wrap=True, origin=neworigin)(trans_u.trajectory.ts) + trans = center_in_axis(ag, axis, center_of='mass', wrap=True, center_from=neworigin)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -370,12 +361,12 @@ def test_center_in_plane_bad_ag(translate_universes): ts = translate_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? bad_ag = 1 - plane = 'x' + plane = 'yz' with pytest.raises(ValueError): center_in_plane(bad_ag, plane)(ts) -@pytest.mark.parametrize('origin', ( +@pytest.mark.parametrize('center_from', ( [0, 1], [0, 1, 2, 3, 4], np.array([0, 1]), @@ -383,16 +374,16 @@ def test_center_in_plane_bad_ag(translate_universes): np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]])) ) -def test_center_in_plane_bad_origin(translate_universes, origin): +def test_center_in_plane_bad_center_from(translate_universes, center_from): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if the box is in the wrong format? - plane = 'x' + plane = 'yz' with pytest.raises(ValueError): - center_in_plane(ag, plane, origin=origin)(ts) + center_in_plane(ag, plane, center_from=center_from)(ts) -@pytest.mark.parametrize('coordinate', ( +@pytest.mark.parametrize('d', ( [0, 1], [0, 1, 2, 3, 4], np.array([0, 1]), @@ -400,13 +391,13 @@ def test_center_in_plane_bad_origin(translate_universes, origin): np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]])) ) -def test_center_in_plane_bad_coordinate(translate_universes, coordinate): +def test_center_in_plane_bad_d(translate_universes, d): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if the box is in the wrong format? - plane = 'x' + plane = 'yz' with pytest.raises(ValueError): - center_in_plane(ag, plane, coordinate=coordinate)(ts) + center_in_plane(ag, plane, d=d)(ts) def test_center_in_plane_bad_pbc(translate_universes): @@ -415,20 +406,20 @@ def test_center_in_plane_bad_pbc(translate_universes): ag = translate_universes[0].residues[0].atoms # is pbc passed to the center methods? # if yes it should raise an exception for boxes that are zero in size - plane = 'x' + plane = 'yz' with pytest.raises(ValueError): center_in_plane(ag, plane, wrap=True)(ts) -def test_center_in_plane_bad_center(translate_universes): +def test_center_in_plane_bad_center_of(translate_universes): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? bad_center = " " - plane = 'x' + plane = 'yz' with pytest.raises(ValueError): - center_in_plane(ag, plane, center=bad_center)(ts) + center_in_plane(ag, plane, center_of=bad_center)(ts) def test_center_in_planes_no_masses(translate_universes): @@ -437,45 +428,45 @@ def test_center_in_planes_no_masses(translate_universes): ag = translate_universes[0].residues[0].atoms # if the universe has no masses and `mass` is passed as the center arg bad_center = "mass" - plane = 'x' + plane = 'yz' with pytest.raises(AttributeError): - center_in_plane(ag, plane, center=bad_center)(ts) + center_in_plane(ag, plane, center_of=bad_center)(ts) def test_center_in_plane_coords_dtype(translate_universes): # is the dtype of the coordinates correct? trans_u = translate_universes[1] - plane = 'x' + plane = 'yz' ag = trans_u.residues[0].atoms trans = center_in_plane(ag, plane)(trans_u.trajectory.ts) assert(trans.positions.dtype == np.float32) def test_center_in_plane_coords_no_options(translate_universes): - # what happens when we center the coordinates arround the center of geometry of a residue? + # what happens when we center the coordinates on a plane without special options? ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts - ref_center = np.float32([6, 7, 8]) + ag = trans_u.residues[0].atoms box_center = np.float32([186., 186.5, 187.]) - plane = 'x' - plane_point = np.float32([0, box_center[1], box_center[2]]) + ref_center = np.float32([6, 7, 8]) + plane = 'yz' + plane_point = box_center ref.positions += plane_point - ref_center - ag = trans_u.residues[0].atoms trans = center_in_plane(ag, plane)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_plane_coords_with_coordinate(translate_universes): +def test_center_in_plane_coords_with_d(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ref_center = np.float32([6, 7, 8]) box_center = np.float32([186., 186.5, 187.]) - coordinate = 10 - plane = 'x' - plane_point = np.float32([coordinate, box_center[1], box_center[2]]) + d = 10 + plane = 'yz' + plane_point = np.float32([box_center[0]+d, box_center[1], box_center[2]]) ref.positions += plane_point - ref_center ag = trans_u.residues[0].atoms - trans = center_in_plane(ag, plane, coordinate=coordinate)(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, d=d)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -488,8 +479,8 @@ def test_center_in_plane_coords_with_pbc(translate_universes): box_center = np.float32([181.5, 182., 182.5]) ag = trans_u.residues[24].atoms ref_center = ag.center_of_geometry(pbc=True) - plane = 'x' - plane_point = np.float32([0, box_center[1], box_center[2]]) + plane = 'yz' + plane_point = box_center ref.positions += plane_point - ref_center trans = center_in_plane(ag, plane, wrap=True)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -502,39 +493,25 @@ def test_center_in_plane_coords_with_mass(translate_universes): ag = trans_u.residues[24].atoms box_center = np.float32([186., 186.5, 187.]) ref_center = ag.center_of_mass() - plane = 'x' - plane_point = np.float32([0, box_center[1], box_center[2]]) + plane = 'yz' + plane_point = box_center ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, center="mass")(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, center_of="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_plane_coords_with_coord_origin(translate_universes): - # what happens when we use a custom coordinate as origin point? - ref_u, trans_u = translate_universes - ref = ref_u.trajectory.ts - ag = trans_u.residues[0].atoms - origin = [1000, 1000, 1000] - box_center = np.float32([186., 186.5, 187.]) - ref_center = np.float32([6, 7, 8]) - plane = 'x' - plane_point = np.float32([origin[0], box_center[1], box_center[2]]) - ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, origin=origin)(trans_u.trajectory.ts) - assert_array_almost_equal(trans.positions, ref.positions, decimal=6) - - -def test_center_in_plane_coords_with_center_origin(translate_universes): - # what happens when we use the center of the unit cell as origin point? +def test_center_in_plane_coords_with_coord_center_from(translate_universes): + # what happens when we use a custom coordinate as center_from point? ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[0].atoms + center_from = [1000, 1000, 1000] box_center = np.float32([186., 186.5, 187.]) ref_center = np.float32([6, 7, 8]) - plane = 'x' - plane_point = box_center + plane = 'yz' + plane_point = np.float32([center_from[0], box_center[1], box_center[2]]) ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, origin='center')(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, center_from=center_from)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -547,12 +524,12 @@ def test_center_in_plane_coords_all_options(translate_universes): trans_u.dimensions = [363., 364., 365., 90., 90., 90.] box_center = np.float32([181.5, 182., 182.5]) neworigin = [1000, 1000, 1000] - coordinate = 100 + d = 100 ref_center = ag.center_of_mass(pbc=True) - plane = 'x' - plane_point = np.float32([neworigin[0]+coordinate, box_center[1], box_center[2]]) + plane = 'yz' + plane_point = np.float32([neworigin[0]+d, box_center[1], box_center[2]]) ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, coordinate=coordinate, origin=neworigin, center='mass', wrap=True)(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, d=d, center_from=neworigin, center_of='mass', wrap=True)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -574,8 +551,10 @@ def test_center_in_axis_transformations_api(translate_universes): ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ref_center = np.float32([6, 7, 8]) + box_center = np.float32([186., 186.5, 187.]) + center_from = box_center axis = 'x' - axis_point = np.float32([ref_center[0], 0, 0]) + axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) ref.positions += axis_point - ref_center ag = trans_u.residues[0].atoms trans_u.trajectory.add_transformations(center_in_axis(ag, axis)) @@ -588,8 +567,8 @@ def test_center_in_plane_transformations_api(translate_universes): ref = ref_u.trajectory.ts ref_center = np.float32([6, 7, 8]) box_center = np.float32([186., 186.5, 187.]) - plane = 'x' - plane_point = np.float32([0, box_center[1], box_center[2]]) + plane = 'yz' + plane_point = box_center ref.positions += plane_point - ref_center ag = trans_u.residues[0].atoms trans_u.trajectory.add_transformations(center_in_plane(ag, plane)) From 1a1ea9efa7a8212a66f62ad8db6c5bea00826b0a Mon Sep 17 00:00:00 2001 From: davidercruz Date: Sat, 21 Jul 2018 02:30:40 +0100 Subject: [PATCH 05/16] removed ifs; removed d arg --- .../MDAnalysis/transformations/translate.py | 84 ++++++++---------- .../transformations/test_translate.py | 87 ++++++------------- 2 files changed, 61 insertions(+), 110 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index f106a83613b..870e47e5a5e 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -152,22 +152,22 @@ def wrapped(ts): return wrapped -def center_in_plane(ag, plane, d=0, center_from="center", center_of='geometry', wrap=False): +def center_in_plane(ag, plane, center_to="center", center_of='geometry', wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` - is centered on a plane. This plane can only be parallel to the yz, xz or xy planes. + is centered on a plane. This plane can be the yz, xz or xy planes. Example ------- Translate the center of mass of the second residue of the universe u to the center of the - x=1 plane: + xy plane: .. code-block:: python ag = u.residues[1].atoms - transform = MDAnalysis.transformations.center_in_plane(ag, yz, 1, center_of='mass') + transform = MDAnalysis.transformations.center_in_plane(ag, xy, center_of='mass') u.trajectory.add_transformations(transform) Parameters @@ -175,14 +175,9 @@ def center_in_plane(ag, plane, d=0, center_from="center", center_of='geometry', ag: AtomGroup atom group to be centered on the unit cell. plane: str - used to define the plane on which the given AtomGroup will be centered. Defined as - a string or an array-like of the plane and the value of its translation. Suported + used to define the plane on which the given AtomGroup will be centered. Suported planes are yz, xz and xy planes. - d: scalar - point where the plane crosses its perpendicular axis. This value is the constant d - on the general plane equation ax + by + cz +d = 0 for the yz, xz and xy planes. - Default is 0 (zero). - center_from: array-like or str + center_to: array-like or str coordinate from which the axes are centered. Can be an array of three coordinate values or `center` which centers the AtomGroup coordinates on the center of the unit cell. Default is `center`. @@ -204,16 +199,16 @@ def center_in_plane(ag, plane, d=0, center_from="center", center_of='geometry', if plane is not None: if plane not in ('xy', 'yz', 'xz'): raise ValueError('{} is not a valid plane'.format(plane)) - if not isinstance(d, Number): - raise ValueError('{} is not a valid value for d'.format(d)) - if center_from is not None: - if isinstance(center_from, string_types): - if not center_from == 'center': - raise ValueError('{} is not a valid "center_from"'.format(center_from)) + axes = {'yz' : 0, 'xz' : 1, 'xy' : 2} + plane = axes[plane] + if center_to is not None: + if isinstance(center_to, string_types): + if not center_to == 'center': + raise ValueError('{} is not a valid "center_to"'.format(center_to)) else: - center_from = np.asarray(center_from, np.float32) - if center_from.shape != (3, ) and center_from.shape != (1, 3): - raise ValueError('{} is not a valid "center_from"'.format(center_from)) + center_to = np.asarray(center_to, np.float32) + if center_to.shape != (3, ) and center_to.shape != (1, 3): + raise ValueError('{} is not a valid "center_to"'.format(center_to)) try: if center_of == 'geometry': center_method = partial(ag.center_of_geometry, pbc=pbc_arg) @@ -229,19 +224,10 @@ def center_in_plane(ag, plane, d=0, center_from="center", center_of='geometry', def wrapped(ts): boxcenter = ts.triclinic_dimensions.sum(axis=0) / 2.0 - if isinstance(center_from, string_types) and center_from == 'center': - _origin = boxcenter - else: - _origin = center_from - if plane == 'yz': - shift = _origin[0]+d - position = [shift, boxcenter[1], boxcenter[2]] - if plane == 'xz': - shift = _origin[1]+d - position = [boxcenter[0], shift, boxcenter[2]] - if plane == 'xy': - shift = _origin[2]+d - position = [boxcenter[0], boxcenter[1], shift] + position = boxcenter + if center_to != 'center': + _origin = center_to + position[plane] = _origin[plane] vector = np.asarray(position, np.float32) - center_method() ts.positions += vector @@ -250,7 +236,7 @@ def wrapped(ts): return wrapped -def center_in_axis(ag, axis, center_from="center", center_of='geometry', wrap=False): +def center_in_axis(ag, axis, center_to="center", center_of='geometry', wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -276,7 +262,7 @@ def center_in_axis(ag, axis, center_from="center", center_of='geometry', wrap=Fa used to define the plane on which the given AtomGroup will be centered. Defined as a string or an array-like of the plane and the value of its translation. Suported planes are x, y and z. - center_from: array-like or str + center_to: array-like or str coordinate on which the axes are centered. Can be an array of three coordinates or `center` to shift the origin to the center of the unit cell. Default is `None` which sets [0, 0, 0] as the origin of the axis. @@ -297,14 +283,16 @@ def center_in_axis(ag, axis, center_from="center", center_of='geometry', wrap=Fa if axis is not None: if axis not in ('x', 'y', 'z'): raise ValueError('{} is not a valid axis'.format(axis)) - if center_from is not None: - if isinstance(center_from, string_types): - if not center_from == 'center': - raise ValueError('{} is not a valid "center_from"'.format(center_from)) + axes = {'x' : 0, 'y': 1, 'z' : 2} + axis = axes[axis] + if center_to is not None: + if isinstance(center_to, string_types): + if not center_to == 'center': + raise ValueError('{} is not a valid "center_to"'.format(center_to)) else: - center_from = np.asarray(center_from, np.float32) - if center_from.shape != (3, ) and center_from.shape != (1, 3): - raise ValueError('{} is not a valid "center_from"'.format(center_from)) + center_to = np.asarray(center_to, np.float32) + if center_to.shape != (3, ) and center_to.shape != (1, 3): + raise ValueError('{} is not a valid "center_to"'.format(center_to)) try: if center_of == 'geometry': center_method = partial(ag.center_of_geometry, pbc=pbc_arg) @@ -319,17 +307,13 @@ def center_in_axis(ag, axis, center_from="center", center_of='geometry', wrap=Fa raise ValueError('{} is not an AtomGroup object'.format(ag)) def wrapped(ts): - if isinstance(center_from, string_types) and center_from == 'center': + if isinstance(center_to, string_types) and center_to == 'center': _origin = ts.triclinic_dimensions.sum(axis=0) / 2.0 else: - _origin = center_from + _origin = center_to ag_center = center_method() - if axis == 'x': - center = np.asarray([ag_center[0], _origin[1], _origin[2]], np.float32) - if axis == 'y': - center = np.asarray([_origin[0], ag_center[1], _origin[2]], np.float32) - if axis == 'z': - center = np.asarray([_origin[0], _origin[1], ag_center[2]], np.float32) + center = _origin + center[axis] = ag_center[axis] vector = center - ag_center ts.positions += vector diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 60131068d5b..cca9ba7bf6f 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -222,7 +222,7 @@ def test_center_in_axis_bad_ag(translate_universes): center_in_axis(bad_ag, axis)(ts) -@pytest.mark.parametrize('center_from', ( +@pytest.mark.parametrize('center_to', ( [0, 1], [0, 1, 2, 3, 4], np.array([0, 1]), @@ -230,13 +230,13 @@ def test_center_in_axis_bad_ag(translate_universes): np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]])) ) -def test_center_in_axis_bad_center_from(translate_universes, center_from): +def test_center_in_axis_bad_center_to(translate_universes, center_to): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if the box is in the wrong format? axis = 'x' with pytest.raises(ValueError): - center_in_axis(ag, axis, center_from=center_from)(ts) + center_in_axis(ag, axis, center_to=center_to)(ts) def test_center_in_axis_bad_pbc(translate_universes): @@ -286,10 +286,10 @@ def test_center_in_axis_coords_no_options(translate_universes): ref = ref_u.trajectory.ts ag = trans_u.residues[0].atoms box_center = np.float32([186., 186.5, 187.]) - center_from = box_center + center_to = box_center ref_center = np.float32([6, 7, 8]) axis = 'x' - axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) + axis_point = np.float32([ref_center[0], center_to[1], center_to[2]]) ref.positions += axis_point - ref_center trans = center_in_axis(ag, axis)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -303,10 +303,10 @@ def test_center_in_axis_coords_with_pbc(translate_universes): trans_u.dimensions = [363., 364., 365., 90., 90., 90.] ag = trans_u.residues[24].atoms box_center = np.float32([181.5, 182., 182.5]) - center_from = box_center + center_to = box_center ref_center = ag.center_of_geometry(pbc=True) axis = 'x' - axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) + axis_point = np.float32([ref_center[0], center_to[1], center_to[2]]) ref.positions += axis_point - ref_center trans = center_in_axis(ag, axis, wrap=True)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -319,25 +319,25 @@ def test_center_in_axis_coords_with_mass(translate_universes): ag = trans_u.residues[24].atoms ref_center = ag.center_of_mass() box_center = np.float32([186., 186.5, 187.]) - center_from = box_center + center_to = box_center axis = 'x' - axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) + axis_point = np.float32([ref_center[0], center_to[1], center_to[2]]) ref.positions += axis_point - ref_center trans = center_in_axis(ag, axis, center_of="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_axis_coords_with_coord_center_from(translate_universes): - # what happens when we use a custom coordinate as center_from point? +def test_center_in_axis_coords_with_coord_center_to(translate_universes): + # what happens when we use a custom coordinate as center_to point? ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[0].atoms - center_from = [1000, 1000, 1000] + center_to = [1000, 1000, 1000] ref_center = np.float32([6, 7, 8]) axis = 'x' - axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) + axis_point = np.float32([ref_center[0], center_to[1], center_to[2]]) ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, center_from=center_from)(trans_u.trajectory.ts) + trans = center_in_axis(ag, axis, center_to=center_to)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -352,7 +352,7 @@ def test_center_in_axis_coords_all_options(translate_universes): axis = 'x' axis_point = np.float32([ref_center[0], neworigin[1], neworigin[2]]) ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, center_of='mass', wrap=True, center_from=neworigin)(trans_u.trajectory.ts) + trans = center_in_axis(ag, axis, center_of='mass', wrap=True, center_to=neworigin)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -366,7 +366,7 @@ def test_center_in_plane_bad_ag(translate_universes): center_in_plane(bad_ag, plane)(ts) -@pytest.mark.parametrize('center_from', ( +@pytest.mark.parametrize('center_to', ( [0, 1], [0, 1, 2, 3, 4], np.array([0, 1]), @@ -374,30 +374,13 @@ def test_center_in_plane_bad_ag(translate_universes): np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]])) ) -def test_center_in_plane_bad_center_from(translate_universes, center_from): +def test_center_in_plane_bad_center_to(translate_universes, center_to): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if the box is in the wrong format? plane = 'yz' with pytest.raises(ValueError): - center_in_plane(ag, plane, center_from=center_from)(ts) - - -@pytest.mark.parametrize('d', ( - [0, 1], - [0, 1, 2, 3, 4], - np.array([0, 1]), - np.array([0, 1, 2, 3, 4]), - np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), - np.array([[0], [1], [2]])) -) -def test_center_in_plane_bad_d(translate_universes, d): - ts = translate_universes[0].trajectory.ts - ag = translate_universes[0].residues[0].atoms - # what if the box is in the wrong format? - plane = 'yz' - with pytest.raises(ValueError): - center_in_plane(ag, plane, d=d)(ts) + center_in_plane(ag, plane, center_to=center_to)(ts) def test_center_in_plane_bad_pbc(translate_universes): @@ -455,21 +438,6 @@ def test_center_in_plane_coords_no_options(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_plane_coords_with_d(translate_universes): - # what happens when we center the coordinates arround the center of geometry of a residue? - ref_u, trans_u = translate_universes - ref = ref_u.trajectory.ts - ref_center = np.float32([6, 7, 8]) - box_center = np.float32([186., 186.5, 187.]) - d = 10 - plane = 'yz' - plane_point = np.float32([box_center[0]+d, box_center[1], box_center[2]]) - ref.positions += plane_point - ref_center - ag = trans_u.residues[0].atoms - trans = center_in_plane(ag, plane, d=d)(trans_u.trajectory.ts) - assert_array_almost_equal(trans.positions, ref.positions, decimal=6) - - def test_center_in_plane_coords_with_pbc(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? # using pbc into account for center of geometry calculation @@ -500,18 +468,18 @@ def test_center_in_plane_coords_with_mass(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_plane_coords_with_coord_center_from(translate_universes): - # what happens when we use a custom coordinate as center_from point? +def test_center_in_plane_coords_with_coord_center_to(translate_universes): + # what happens when we use a custom coordinate as center_to point? ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[0].atoms - center_from = [1000, 1000, 1000] + center_to = [1000, 1000, 1000] box_center = np.float32([186., 186.5, 187.]) ref_center = np.float32([6, 7, 8]) plane = 'yz' - plane_point = np.float32([center_from[0], box_center[1], box_center[2]]) + plane_point = np.float32([center_to[0], box_center[1], box_center[2]]) ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, center_from=center_from)(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, center_to=center_to)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -524,12 +492,11 @@ def test_center_in_plane_coords_all_options(translate_universes): trans_u.dimensions = [363., 364., 365., 90., 90., 90.] box_center = np.float32([181.5, 182., 182.5]) neworigin = [1000, 1000, 1000] - d = 100 ref_center = ag.center_of_mass(pbc=True) plane = 'yz' - plane_point = np.float32([neworigin[0]+d, box_center[1], box_center[2]]) + plane_point = np.float32([neworigin[0], box_center[1], box_center[2]]) ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, d=d, center_from=neworigin, center_of='mass', wrap=True)(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, center_to=neworigin, center_of='mass', wrap=True)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -552,9 +519,9 @@ def test_center_in_axis_transformations_api(translate_universes): ref = ref_u.trajectory.ts ref_center = np.float32([6, 7, 8]) box_center = np.float32([186., 186.5, 187.]) - center_from = box_center + center_to = box_center axis = 'x' - axis_point = np.float32([ref_center[0], center_from[1], center_from[2]]) + axis_point = np.float32([ref_center[0], center_to[1], center_to[2]]) ref.positions += axis_point - ref_center ag = trans_u.residues[0].atoms trans_u.trajectory.add_transformations(center_in_axis(ag, axis)) From cf645ea64455a8ca683eda97ecf3eed7eeb8c383 Mon Sep 17 00:00:00 2001 From: davidercruz Date: Sun, 22 Jul 2018 04:22:06 +0100 Subject: [PATCH 06/16] all center functions now accept weights ; changed center_in_plane calculation --- .../MDAnalysis/transformations/translate.py | 132 +++++++++--------- .../transformations/test_translate.py | 97 +++++++------ 2 files changed, 126 insertions(+), 103 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 870e47e5a5e..45099cf61db 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -38,6 +38,7 @@ from functools import partial from ..lib.mdamath import triclinic_vectors +from ..lib.util import get_weights def translate(vector): """ @@ -51,7 +52,7 @@ def translate(vector): ..code-block:: python - transform = MDAnalysis.transformations.translate([1,2,3]) + transform = mda.transformations.translate([1,2,3]) u.trajectory.add_transformations(transform) Parameters @@ -77,7 +78,7 @@ def wrapped(ts): return wrapped -def center_in_box(ag, center_of='geometry', point=None, wrap=False): +def center_in_box(ag, weights=None, center_to=None, wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -93,16 +94,19 @@ def center_in_box(ag, center_of='geometry', point=None, wrap=False): .. code-block:: python ag = u.residues[1].atoms - transform = MDAnalysis.transformations.center(ag, center_of='mass') + transform = mda.transformations.center(ag, center_of='mass') u.trajectory.add_transformations(transform) Parameters ---------- ag: AtomGroup atom group to be centered on the unit cell. - center_of: str, optional - used to choose the method of centering on the given atom group. Can be 'geometry' - or 'mass' + weights: {"mass", ``None``} or array_like, optional + define the weights of the atoms when calculating the center of the AtomGroup. + With ``"mass"`` uses masses as weights; with ``None`` weigh each atom equally. + If a float array of the same length as `ag` is provided, use each element of + the `array_like` as a weight for the corresponding atom in `ag`. Default is + None. point: array-like, optional overrides the unit cell center - the coordinates of the Timestep are translated so that the center of mass/geometry of the given AtomGroup is aligned to this position @@ -119,28 +123,25 @@ def center_in_box(ag, center_of='geometry', point=None, wrap=False): """ pbc_arg = wrap - if point: - point = np.asarray(point, np.float32) - if point.shape != (3, ) and point.shape != (1, 3): - raise ValueError('{} is not a valid point'.format(point)) + if center_to: + center_to = np.asarray(center_to, np.float32) + if center_to.shape != (3, ) and center_to.shape != (1, 3): + raise ValueError('{} is not a valid point'.format(center_to)) try: - if center_of == 'geometry': - center_method = partial(ag.center_of_geometry, pbc=pbc_arg) - elif center_of == 'mass': - center_method = partial(ag.center_of_mass, pbc=pbc_arg) - else: - raise ValueError('{} is not a valid argument for "center_of"'.format(center_of)) + weights = get_weights(ag.atoms, weights=weights) + except (ValueError, TypeError): + raise TypeError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup.") + try: + center_method = partial(ag.atoms.center, weights, pbc=wrap) except AttributeError: - if center_of == 'mass': - raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) - else: - raise ValueError('{} is not an AtomGroup object'.format(ag)) + raise ValueError('{} is not an AtomGroup object'.format(ag)) def wrapped(ts): - if point is None: + if center_to is None: boxcenter = np.sum(ts.triclinic_dimensions, axis=0) / 2 else: - boxcenter = point + boxcenter = center_to ag_center = center_method() @@ -152,7 +153,7 @@ def wrapped(ts): return wrapped -def center_in_plane(ag, plane, center_to="center", center_of='geometry', wrap=False): +def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -167,7 +168,7 @@ def center_in_plane(ag, plane, center_to="center", center_of='geometry', wrap=Fa .. code-block:: python ag = u.residues[1].atoms - transform = MDAnalysis.transformations.center_in_plane(ag, xy, center_of='mass') + transform = mda.transformations.center_in_plane(ag, xy, weights='mass') u.trajectory.add_transformations(transform) Parameters @@ -178,12 +179,15 @@ def center_in_plane(ag, plane, center_to="center", center_of='geometry', wrap=Fa used to define the plane on which the given AtomGroup will be centered. Suported planes are yz, xz and xy planes. center_to: array-like or str - coordinate from which the axes are centered. Can be an array of three coordinate + coordinates to which the axes are centered. Can be an array of three coordinate values or `center` which centers the AtomGroup coordinates on the center of the unit cell. Default is `center`. - center_of: str, optional - used to choose the method of centering on the given atom group. Can be 'geometry' - or 'mass' + weights: {"mass", ``None``} or array_like, optional + define the weights of the atoms when calculating the center of the AtomGroup. + With ``"mass"`` uses masses as weights; with ``None`` weigh each atom equally. + If a float array of the same length as `ag` is provided, use each element of + the `array_like` as a weight for the corresponding atom in `ag`. Default is + None. wrap: bool, optional If `True`, all the atoms from the given AtomGroup will be moved to the unit cell before calculating the center of mass or geometry. Default is `False`, no changes @@ -194,13 +198,10 @@ def center_in_plane(ag, plane, center_to="center", center_of='geometry', wrap=Fa MDAnalysis.coordinates.base.Timestep """ - - pbc_arg = wrap - if plane is not None: - if plane not in ('xy', 'yz', 'xz'): - raise ValueError('{} is not a valid plane'.format(plane)) - axes = {'yz' : 0, 'xz' : 1, 'xy' : 2} - plane = axes[plane] + if plane not in ('xy', 'yz', 'xz'): + raise ValueError('{} is not a valid plane'.format(plane)) + axes = {'yz' : 0, 'xz' : 1, 'xy' : 2} + plane = axes[plane] if center_to is not None: if isinstance(center_to, string_types): if not center_to == 'center': @@ -209,25 +210,26 @@ def center_in_plane(ag, plane, center_to="center", center_of='geometry', wrap=Fa center_to = np.asarray(center_to, np.float32) if center_to.shape != (3, ) and center_to.shape != (1, 3): raise ValueError('{} is not a valid "center_to"'.format(center_to)) + else: + center_to = center_to.reshape(3, ) try: - if center_of == 'geometry': - center_method = partial(ag.center_of_geometry, pbc=pbc_arg) - elif center_of == 'mass': - center_method = partial(ag.center_of_mass, pbc=pbc_arg) - else: - raise ValueError('{} is not a valid argument for "center_of"'.format(center_of)) + weights = get_weights(ag.atoms, weights=weights) + except (ValueError, TypeError): + raise TypeError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup.") + try: + center_method = partial(ag.atoms.center, weights, pbc=wrap) except AttributeError: - if center_of == 'mass': - raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) - else: - raise ValueError('{} is not an AtomGroup object'.format(ag)) + raise ValueError('{} is not an AtomGroup object'.format(ag)) def wrapped(ts): boxcenter = ts.triclinic_dimensions.sum(axis=0) / 2.0 - position = boxcenter - if center_to != 'center': + if center_to == 'center': + _origin = boxcenter + else: _origin = center_to - position[plane] = _origin[plane] + position = center_method() + position[plane] = _origin[plane] vector = np.asarray(position, np.float32) - center_method() ts.positions += vector @@ -236,7 +238,7 @@ def wrapped(ts): return wrapped -def center_in_axis(ag, axis, center_to="center", center_of='geometry', wrap=False): +def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -251,7 +253,7 @@ def center_in_axis(ag, axis, center_to="center", center_of='geometry', wrap=Fals .. code-block:: python ag = u.residues[1].atoms - transform = MDAnalysis.transformations.center_in_axis(ag, 'x', [0,0,1], center_of='mass') + transform = mda.transformations.center_in_axis(ag, 'x', [0,0,1], center_of='mass') u.trajectory.add_transformation(transform) Parameters @@ -266,9 +268,12 @@ def center_in_axis(ag, axis, center_to="center", center_of='geometry', wrap=Fals coordinate on which the axes are centered. Can be an array of three coordinates or `center` to shift the origin to the center of the unit cell. Default is `None` which sets [0, 0, 0] as the origin of the axis. - center_of: str, optional - used to choose the method of centering on the given atom group. Can be 'geometry' - or 'mass' + weights: {"mass", ``None``} or array_like, optional + define the weights of the atoms when calculating the center of the AtomGroup. + With ``"mass"`` uses masses as weights; with ``None`` weigh each atom equally. + If a float array of the same length as `ag` is provided, use each element of + the `array_like` as a weight for the corresponding atom in `ag`. Default is + None. wrap: bool, optional If `True`, all the atoms from the given AtomGroup will be moved to the unit cell before calculating the center of mass or geometry. Default is `False`, no changes @@ -293,21 +298,20 @@ def center_in_axis(ag, axis, center_to="center", center_of='geometry', wrap=Fals center_to = np.asarray(center_to, np.float32) if center_to.shape != (3, ) and center_to.shape != (1, 3): raise ValueError('{} is not a valid "center_to"'.format(center_to)) + else: + center_to = center_to.reshape(3, ) try: - if center_of == 'geometry': - center_method = partial(ag.center_of_geometry, pbc=pbc_arg) - elif center_of == 'mass': - center_method = partial(ag.center_of_mass, pbc=pbc_arg) - else: - raise ValueError('{} is not a valid argument for "center_of"'.format(center_of)) + weights = get_weights(ag.atoms, weights=weights) + except (ValueError, TypeError): + raise TypeError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup.") + try: + center_method = partial(ag.atoms.center, weights, pbc=wrap) except AttributeError: - if center_of == 'mass': - raise AttributeError('{} is not an AtomGroup object with masses'.format(ag)) - else: - raise ValueError('{} is not an AtomGroup object'.format(ag)) + raise ValueError('{} is not an AtomGroup object'.format(ag)) def wrapped(ts): - if isinstance(center_to, string_types) and center_to == 'center': + if center_to == 'center': _origin = ts.triclinic_dimensions.sum(axis=0) / 2.0 else: _origin = center_to diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index cca9ba7bf6f..d21dbbcc5ad 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -90,11 +90,11 @@ def test_center_in_box_bad_ag(translate_universes): ts = translate_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? bad_ag = 1 - with pytest.raises(ValueError): + with pytest.raises(AttributeError): center_in_box(bad_ag)(ts) -@pytest.mark.parametrize('point', ( +@pytest.mark.parametrize('center_to', ( [0, 1], [0, 1, 2, 3, 4], np.array([0, 1]), @@ -102,12 +102,13 @@ def test_center_in_box_bad_ag(translate_universes): np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]])) ) -def test_center_in_box_bad_point(translate_universes, point): +def test_center_in_box_bad_center_to(translate_universes, center_to): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms + bad_center_to = center_to # what if the box is in the wrong format? with pytest.raises(ValueError): - center_in_box(ag, point=point)(ts) + center_in_box(ag, center_to=bad_center_to)(ts) def test_center_in_box_bad_pbc(translate_universes): @@ -120,14 +121,23 @@ def test_center_in_box_bad_pbc(translate_universes): center_in_box(ag, wrap=True)(ts) -def test_center_in_box_bad_center(translate_universes): +@pytest.mark.parametrize('weights', ( + " ", + "totallynotmasses", + 123456789, + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])) +) +def test_center_in_box_bad_weights(translate_universes, weights): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? - bad_center = " " - with pytest.raises(ValueError): - center_in_box(ag, center_of=bad_center)(ts) + bad_weights = " " + with pytest.raises(TypeError): + center_in_box(ag, weights=bad_weights)(ts) def test_center_in_box_no_masses(translate_universes): @@ -136,7 +146,7 @@ def test_center_in_box_no_masses(translate_universes): ag = translate_universes[0].residues[0].atoms # if the universe has no masses and `mass` is passed as the center arg bad_center = "mass" - with pytest.raises(AttributeError): + with pytest.raises(TypeError): center_in_box(ag, center_of=bad_center)(ts) @@ -182,7 +192,7 @@ def test_center_in_box_coords_with_mass(translate_universes): box_center = np.float32([186., 186.5, 187.]) ref_center = ag.center_of_mass() ref.positions += box_center - ref_center - trans = center_in_box(ag, center_of="mass")(trans_u.trajectory.ts) + trans = center_in_box(ag, weights="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -195,7 +205,7 @@ def test_center_in_box_coords_with_box(translate_universes): box_center = np.float32(newpoint) ref_center = np.float32([6, 7, 8]) ref.positions += box_center - ref_center - trans = center_in_box(ag, point=newpoint)(trans_u.trajectory.ts) + trans = center_in_box(ag, center_to=newpoint)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -209,7 +219,7 @@ def test_center_in_box_coords_all_options(translate_universes): box_center = np.float32(newpoint) ref_center = ag.center_of_mass(pbc=True) ref.positions += box_center - ref_center - trans = center_in_box(ag, center_of='mass', wrap=True, point=newpoint)(trans_u.trajectory.ts) + trans = center_in_box(ag, weights='mass', wrap=True, center_to=newpoint)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) def test_center_in_axis_bad_ag(translate_universes): @@ -218,7 +228,7 @@ def test_center_in_axis_bad_ag(translate_universes): # what happens if something other than an AtomGroup is given? bad_ag = 1 axis = 'x' - with pytest.raises(ValueError): + with pytest.raises(AttributeError): center_in_axis(bad_ag, axis)(ts) @@ -250,15 +260,24 @@ def test_center_in_axis_bad_pbc(translate_universes): center_in_axis(ag,axis, wrap=True)(ts) -def test_center_in_axis_bad_center_of(translate_universes): +@pytest.mark.parametrize('weights', ( + " ", + "totallynotmasses", + 123456789, + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])) +) +def test_center_in_axis_bad_weights(translate_universes, weights): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? - bad_center = " " + bad_weights = " " axis = 'x' - with pytest.raises(ValueError): - center_in_axis(ag, axis, center_of=bad_center)(ts) + with pytest.raises(TypeError): + center_in_axis(ag, axis, weights=bad_weights)(ts) def test_center_in_axis_no_masses(translate_universes): @@ -266,10 +285,10 @@ def test_center_in_axis_no_masses(translate_universes): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # if the universe has no masses and `mass` is passed as the center arg - bad_center = "mass" + bad_weights = "mass" axis = 'x' - with pytest.raises(AttributeError): - center_in_axis(ag, axis, center_of=bad_center)(ts) + with pytest.raises(TypeError): + center_in_axis(ag, axis, weights=bad_weights)(ts) def test_center_in_axis_coords_dtype(translate_universes): # is the dtype of the coordinates correct? @@ -323,7 +342,7 @@ def test_center_in_axis_coords_with_mass(translate_universes): axis = 'x' axis_point = np.float32([ref_center[0], center_to[1], center_to[2]]) ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, center_of="mass")(trans_u.trajectory.ts) + trans = center_in_axis(ag, axis, weights="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -352,7 +371,7 @@ def test_center_in_axis_coords_all_options(translate_universes): axis = 'x' axis_point = np.float32([ref_center[0], neworigin[1], neworigin[2]]) ref.positions += axis_point - ref_center - trans = center_in_axis(ag, axis, center_of='mass', wrap=True, center_to=neworigin)(trans_u.trajectory.ts) + trans = center_in_axis(ag, axis, weights='mass', wrap=True, center_to=neworigin)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -362,7 +381,7 @@ def test_center_in_plane_bad_ag(translate_universes): # what happens if something other than an AtomGroup is given? bad_ag = 1 plane = 'yz' - with pytest.raises(ValueError): + with pytest.raises(AttributeError): center_in_plane(bad_ag, plane)(ts) @@ -394,15 +413,15 @@ def test_center_in_plane_bad_pbc(translate_universes): center_in_plane(ag, plane, wrap=True)(ts) -def test_center_in_plane_bad_center_of(translate_universes): +def test_center_in_plane_bad_weights(translate_universes): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? - bad_center = " " + bad_weights = " " plane = 'yz' - with pytest.raises(ValueError): - center_in_plane(ag, plane, center_of=bad_center)(ts) + with pytest.raises(TypeError): + center_in_plane(ag, plane, weights=bad_weights)(ts) def test_center_in_planes_no_masses(translate_universes): @@ -410,10 +429,10 @@ def test_center_in_planes_no_masses(translate_universes): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # if the universe has no masses and `mass` is passed as the center arg - bad_center = "mass" + weights = "mass" plane = 'yz' - with pytest.raises(AttributeError): - center_in_plane(ag, plane, center_of=bad_center)(ts) + with pytest.raises(TypeError): + center_in_plane(ag, plane, weights=weights)(ts) def test_center_in_plane_coords_dtype(translate_universes): # is the dtype of the coordinates correct? @@ -432,7 +451,7 @@ def test_center_in_plane_coords_no_options(translate_universes): box_center = np.float32([186., 186.5, 187.]) ref_center = np.float32([6, 7, 8]) plane = 'yz' - plane_point = box_center + plane_point = np.asarray([box_center[0], ref_center[1], ref_center[2]], np.float32) ref.positions += plane_point - ref_center trans = center_in_plane(ag, plane)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -448,7 +467,7 @@ def test_center_in_plane_coords_with_pbc(translate_universes): ag = trans_u.residues[24].atoms ref_center = ag.center_of_geometry(pbc=True) plane = 'yz' - plane_point = box_center + plane_point = np.asarray([box_center[0], ref_center[1], ref_center[2]], np.float32) ref.positions += plane_point - ref_center trans = center_in_plane(ag, plane, wrap=True)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -462,9 +481,9 @@ def test_center_in_plane_coords_with_mass(translate_universes): box_center = np.float32([186., 186.5, 187.]) ref_center = ag.center_of_mass() plane = 'yz' - plane_point = box_center + plane_point = np.asarray([box_center[0], ref_center[1], ref_center[2]], np.float32) ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, center_of="mass")(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, weights="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -477,7 +496,7 @@ def test_center_in_plane_coords_with_coord_center_to(translate_universes): box_center = np.float32([186., 186.5, 187.]) ref_center = np.float32([6, 7, 8]) plane = 'yz' - plane_point = np.float32([center_to[0], box_center[1], box_center[2]]) + plane_point = np.float32([center_to[0], ref_center[1], ref_center[2]]) ref.positions += plane_point - ref_center trans = center_in_plane(ag, plane, center_to=center_to)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -491,12 +510,12 @@ def test_center_in_plane_coords_all_options(translate_universes): ag = trans_u.residues[24].atoms trans_u.dimensions = [363., 364., 365., 90., 90., 90.] box_center = np.float32([181.5, 182., 182.5]) - neworigin = [1000, 1000, 1000] + center_to = [1000, 1000, 1000] ref_center = ag.center_of_mass(pbc=True) plane = 'yz' - plane_point = np.float32([neworigin[0], box_center[1], box_center[2]]) + plane_point = np.float32([center_to[0], ref_center[1], ref_center[2]]) ref.positions += plane_point - ref_center - trans = center_in_plane(ag, plane, center_to=neworigin, center_of='mass', wrap=True)(trans_u.trajectory.ts) + trans = center_in_plane(ag, plane, center_to=center_to, weights='mass', wrap=True)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -535,7 +554,7 @@ def test_center_in_plane_transformations_api(translate_universes): ref_center = np.float32([6, 7, 8]) box_center = np.float32([186., 186.5, 187.]) plane = 'yz' - plane_point = box_center + plane_point = np.asarray([box_center[0], ref_center[1], ref_center[2]], np.float32) ref.positions += plane_point - ref_center ag = trans_u.residues[0].atoms trans_u.trajectory.add_transformations(center_in_plane(ag, plane)) From 24d9cc5929245c5dd2368eef0495be9db3b78e5c Mon Sep 17 00:00:00 2001 From: davidercruz Date: Sun, 22 Jul 2018 04:33:46 +0100 Subject: [PATCH 07/16] code cleanup --- package/MDAnalysis/transformations/translate.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 45099cf61db..593d6b93ba1 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -127,6 +127,8 @@ def center_in_box(ag, weights=None, center_to=None, wrap=False): center_to = np.asarray(center_to, np.float32) if center_to.shape != (3, ) and center_to.shape != (1, 3): raise ValueError('{} is not a valid point'.format(center_to)) + else: + center_to = center_to.reshape(3, ) try: weights = get_weights(ag.atoms, weights=weights) except (ValueError, TypeError): @@ -284,12 +286,10 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): MDAnalysis.coordinates.base.Timestep """ - pbc_arg = wrap - if axis is not None: - if axis not in ('x', 'y', 'z'): - raise ValueError('{} is not a valid axis'.format(axis)) - axes = {'x' : 0, 'y': 1, 'z' : 2} - axis = axes[axis] + if axis not in ('x', 'y', 'z'): + raise ValueError('{} is not a valid axis'.format(axis)) + axes = {'x' : 0, 'y': 1, 'z' : 2} + axis = axes[axis] if center_to is not None: if isinstance(center_to, string_types): if not center_to == 'center': From e205dc4ac1ced46e0825ce8a3e56abf2ce66a197 Mon Sep 17 00:00:00 2001 From: davidercruz Date: Sun, 22 Jul 2018 12:29:19 +0100 Subject: [PATCH 08/16] improved exceptions; improved tests coverage --- .../MDAnalysis/transformations/translate.py | 68 +++++++++++-------- .../transformations/test_translate.py | 52 ++++++++++++-- 2 files changed, 86 insertions(+), 34 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 593d6b93ba1..c60a81444bd 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -130,14 +130,16 @@ def center_in_box(ag, weights=None, center_to=None, wrap=False): else: center_to = center_to.reshape(3, ) try: - weights = get_weights(ag.atoms, weights=weights) - except (ValueError, TypeError): - raise TypeError("weights must be {'mass', None} or an iterable of the " - "same size as the atomgroup.") - try: - center_method = partial(ag.atoms.center, weights, pbc=wrap) + atoms = ag.atoms except AttributeError: raise ValueError('{} is not an AtomGroup object'.format(ag)) + else: + try: + weights = get_weights(atoms, weights=weights) + except (ValueError, TypeError): + raise TypeError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup.") + center_method = partial(atoms.center, weights, pbc=wrap) def wrapped(ts): if center_to is None: @@ -200,10 +202,11 @@ def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): MDAnalysis.coordinates.base.Timestep """ - if plane not in ('xy', 'yz', 'xz'): + try: + axes = {'yz' : 0, 'xz' : 1, 'xy' : 2} + plane = axes[plane] + except (KeyError, TypeError): raise ValueError('{} is not a valid plane'.format(plane)) - axes = {'yz' : 0, 'xz' : 1, 'xy' : 2} - plane = axes[plane] if center_to is not None: if isinstance(center_to, string_types): if not center_to == 'center': @@ -215,14 +218,16 @@ def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): else: center_to = center_to.reshape(3, ) try: - weights = get_weights(ag.atoms, weights=weights) - except (ValueError, TypeError): - raise TypeError("weights must be {'mass', None} or an iterable of the " - "same size as the atomgroup.") - try: - center_method = partial(ag.atoms.center, weights, pbc=wrap) + atoms = ag.atoms except AttributeError: raise ValueError('{} is not an AtomGroup object'.format(ag)) + else: + try: + weights = get_weights(atoms, weights=weights) + except (ValueError, TypeError): + raise TypeError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup.") + center_method = partial(atoms.center, weights, pbc=wrap) def wrapped(ts): boxcenter = ts.triclinic_dimensions.sum(axis=0) / 2.0 @@ -286,29 +291,34 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): MDAnalysis.coordinates.base.Timestep """ - if axis not in ('x', 'y', 'z'): + try: + axes = {'x' : 0, 'y': 1, 'z' : 2} + axis = axes[axis] + except (KeyError, TypeError): raise ValueError('{} is not a valid axis'.format(axis)) - axes = {'x' : 0, 'y': 1, 'z' : 2} - axis = axes[axis] if center_to is not None: if isinstance(center_to, string_types): - if not center_to == 'center': + if center_to != 'center': raise ValueError('{} is not a valid "center_to"'.format(center_to)) else: - center_to = np.asarray(center_to, np.float32) - if center_to.shape != (3, ) and center_to.shape != (1, 3): - raise ValueError('{} is not a valid "center_to"'.format(center_to)) - else: + try: + center_to = np.asarray(center_to, np.float32) + if center_to.shape != (3, ) and center_to.shape != (1, 3): + raise ValueError('{} is not a valid "center_to"'.format(center_to)) center_to = center_to.reshape(3, ) + except ValueError: + raise ValueError('{} is not a valid "center_to"'.format(center_to)) try: - weights = get_weights(ag.atoms, weights=weights) - except (ValueError, TypeError): - raise TypeError("weights must be {'mass', None} or an iterable of the " - "same size as the atomgroup.") - try: - center_method = partial(ag.atoms.center, weights, pbc=wrap) + atoms = ag.atoms except AttributeError: raise ValueError('{} is not an AtomGroup object'.format(ag)) + else: + try: + weights = get_weights(atoms, weights=weights) + except (ValueError, TypeError): + raise TypeError("weights must be {'mass', None} or an iterable of the " + "same size as the atomgroup.") + center_method = partial(ag.atoms.center, weights, pbc=wrap) def wrapped(ts): if center_to == 'center': diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index d21dbbcc5ad..4e6c6c2f04f 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -90,7 +90,7 @@ def test_center_in_box_bad_ag(translate_universes): ts = translate_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? bad_ag = 1 - with pytest.raises(AttributeError): + with pytest.raises(ValueError): center_in_box(bad_ag)(ts) @@ -228,7 +228,7 @@ def test_center_in_axis_bad_ag(translate_universes): # what happens if something other than an AtomGroup is given? bad_ag = 1 axis = 'x' - with pytest.raises(AttributeError): + with pytest.raises(ValueError): center_in_axis(bad_ag, axis)(ts) @@ -238,7 +238,10 @@ def test_center_in_axis_bad_ag(translate_universes): np.array([0, 1]), np.array([0, 1, 2, 3, 4]), np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), - np.array([[0], [1], [2]])) + np.array([[0], [1], [2]]), + b'center', + 'thisisnotacenter', + 1) ) def test_center_in_axis_bad_center_to(translate_universes, center_to): ts = translate_universes[0].trajectory.ts @@ -248,6 +251,24 @@ def test_center_in_axis_bad_center_to(translate_universes, center_to): with pytest.raises(ValueError): center_in_axis(ag, axis, center_to=center_to)(ts) + +@pytest.mark.parametrize('axis', ( + 1, + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + "xyz", + "notanaxis", + b'x') +) +def test_center_in_axis_bad_axis(translate_universes, axis): + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # what if the box is in the wrong format? + bad_axis = axis + with pytest.raises(ValueError): + center_in_axis(ag, bad_axis)(ts) + def test_center_in_axis_bad_pbc(translate_universes): # this universe has a box size zero @@ -381,7 +402,7 @@ def test_center_in_plane_bad_ag(translate_universes): # what happens if something other than an AtomGroup is given? bad_ag = 1 plane = 'yz' - with pytest.raises(AttributeError): + with pytest.raises(ValueError): center_in_plane(bad_ag, plane)(ts) @@ -391,7 +412,10 @@ def test_center_in_plane_bad_ag(translate_universes): np.array([0, 1]), np.array([0, 1, 2, 3, 4]), np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), - np.array([[0], [1], [2]])) + np.array([[0], [1], [2]]), + b'center', + 'thisisnotacenter', + 1) ) def test_center_in_plane_bad_center_to(translate_universes, center_to): ts = translate_universes[0].trajectory.ts @@ -401,6 +425,24 @@ def test_center_in_plane_bad_center_to(translate_universes, center_to): with pytest.raises(ValueError): center_in_plane(ag, plane, center_to=center_to)(ts) + +@pytest.mark.parametrize('plane', ( + 1, + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + "xyz", + "notaplane", + b'xy') +) +def test_center_in_plane_bad_plane(translate_universes, plane): + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # what if the box is in the wrong format? + bad_plane = plane + with pytest.raises(ValueError): + center_in_plane(ag, bad_plane)(ts) + def test_center_in_plane_bad_pbc(translate_universes): # this universe has a box size zero From 212ca07cdc934479cf06b244cb29ec60c10a732b Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Sun, 22 Jul 2018 21:27:18 +0100 Subject: [PATCH 09/16] byte strings were causing tests to fail on python2.7 --- .../MDAnalysis/transformations/translate.py | 18 +++--- .../transformations/test_translate.py | 55 ++++++++++++++----- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index c60a81444bd..19bed19e5fa 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -207,16 +207,16 @@ def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): plane = axes[plane] except (KeyError, TypeError): raise ValueError('{} is not a valid plane'.format(plane)) - if center_to is not None: - if isinstance(center_to, string_types): - if not center_to == 'center': - raise ValueError('{} is not a valid "center_to"'.format(center_to)) + + if isinstance(center_to, string_types): + if not center_to == 'center': + raise ValueError('{} is not a valid "center_to"'.format(center_to)) + else: + center_to = np.asarray(center_to, np.float32) + if center_to.shape != (3, ) and center_to.shape != (1, 3): + raise ValueError('{} is not a valid "center_to"'.format(center_to)) else: - center_to = np.asarray(center_to, np.float32) - if center_to.shape != (3, ) and center_to.shape != (1, 3): - raise ValueError('{} is not a valid "center_to"'.format(center_to)) - else: - center_to = center_to.reshape(3, ) + center_to = center_to.reshape(3, ) try: atoms = ag.atoms except AttributeError: diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 4e6c6c2f04f..02b451253cc 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -85,11 +85,21 @@ def test_translate_transformations_api(translate_universes): assert_array_almost_equal(trans_u.trajectory.ts.positions, ref.positions, decimal=6) -def test_center_in_box_bad_ag(translate_universes): +@pytest.mark.parametrize('ag', ( + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), + np.array([[0], [1], [2]]), + 'thisisnotanag', + 1) +) +def test_center_in_box_bad_ag(translate_universes, ag): # this universe has a box size zero ts = translate_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? - bad_ag = 1 + bad_ag = ag with pytest.raises(ValueError): center_in_box(bad_ag)(ts) @@ -100,7 +110,9 @@ def test_center_in_box_bad_ag(translate_universes): np.array([0, 1]), np.array([0, 1, 2, 3, 4]), np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), - np.array([[0], [1], [2]])) + np.array([[0], [1], [2]]), + 'thisisnotacenter', + 1) ) def test_center_in_box_bad_center_to(translate_universes, center_to): ts = translate_universes[0].trajectory.ts @@ -222,11 +234,22 @@ def test_center_in_box_coords_all_options(translate_universes): trans = center_in_box(ag, weights='mass', wrap=True, center_to=newpoint)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_axis_bad_ag(translate_universes): + +@pytest.mark.parametrize('ag', ( + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), + np.array([[0], [1], [2]]), + 'thisisnotanag', + 1) +) +def test_center_in_axis_bad_ag(translate_universes, ag): # this universe has a box size zero ts = translate_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? - bad_ag = 1 + bad_ag = ag axis = 'x' with pytest.raises(ValueError): center_in_axis(bad_ag, axis)(ts) @@ -239,7 +262,6 @@ def test_center_in_axis_bad_ag(translate_universes): np.array([0, 1, 2, 3, 4]), np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]]), - b'center', 'thisisnotacenter', 1) ) @@ -258,8 +280,7 @@ def test_center_in_axis_bad_center_to(translate_universes, center_to): [0, 1, 2, 3, 4], np.array([0, 1]), "xyz", - "notanaxis", - b'x') + "notanaxis") ) def test_center_in_axis_bad_axis(translate_universes, axis): ts = translate_universes[0].trajectory.ts @@ -396,11 +417,21 @@ def test_center_in_axis_coords_all_options(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_plane_bad_ag(translate_universes): +@pytest.mark.parametrize('ag', ( + [0, 1], + [0, 1, 2, 3, 4], + np.array([0, 1]), + np.array([0, 1, 2, 3, 4]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), + np.array([[0], [1], [2]]), + 'thisisnotanag', + 1) +) +def test_center_in_plane_bad_ag(translate_universes, ag): # this universe has a box size zero ts = translate_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? - bad_ag = 1 + bad_ag = ag plane = 'yz' with pytest.raises(ValueError): center_in_plane(bad_ag, plane)(ts) @@ -413,7 +444,6 @@ def test_center_in_plane_bad_ag(translate_universes): np.array([0, 1, 2, 3, 4]), np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]), np.array([[0], [1], [2]]), - b'center', 'thisisnotacenter', 1) ) @@ -432,8 +462,7 @@ def test_center_in_plane_bad_center_to(translate_universes, center_to): [0, 1, 2, 3, 4], np.array([0, 1]), "xyz", - "notaplane", - b'xy') + "notaplane") ) def test_center_in_plane_bad_plane(translate_universes, plane): ts = translate_universes[0].trajectory.ts From 2a46e04d372953c065d16352192f6d70bd9e4a0b Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Sun, 22 Jul 2018 21:34:31 +0100 Subject: [PATCH 10/16] more cleanup --- .../MDAnalysis/transformations/translate.py | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 19bed19e5fa..20621ae54cb 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -296,18 +296,17 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): axis = axes[axis] except (KeyError, TypeError): raise ValueError('{} is not a valid axis'.format(axis)) - if center_to is not None: - if isinstance(center_to, string_types): - if center_to != 'center': - raise ValueError('{} is not a valid "center_to"'.format(center_to)) - else: - try: - center_to = np.asarray(center_to, np.float32) - if center_to.shape != (3, ) and center_to.shape != (1, 3): - raise ValueError('{} is not a valid "center_to"'.format(center_to)) - center_to = center_to.reshape(3, ) - except ValueError: + if isinstance(center_to, string_types): + if center_to != 'center': + raise ValueError('{} is not a valid "center_to"'.format(center_to)) + else: + try: + center_to = np.asarray(center_to, np.float32) + if center_to.shape != (3, ) and center_to.shape != (1, 3): raise ValueError('{} is not a valid "center_to"'.format(center_to)) + center_to = center_to.reshape(3, ) + except ValueError: + raise ValueError('{} is not a valid "center_to"'.format(center_to)) try: atoms = ag.atoms except AttributeError: @@ -317,7 +316,7 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): weights = get_weights(atoms, weights=weights) except (ValueError, TypeError): raise TypeError("weights must be {'mass', None} or an iterable of the " - "same size as the atomgroup.") + "same size as the atomgroup.") center_method = partial(ag.atoms.center, weights, pbc=wrap) def wrapped(ts): From 0e8788aa110cd8816f91f8a1d168e42756e318d0 Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Sun, 22 Jul 2018 22:47:14 +0100 Subject: [PATCH 11/16] code cleanup --- .../MDAnalysis/transformations/translate.py | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 20621ae54cb..066eb8dbde1 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -207,16 +207,14 @@ def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): plane = axes[plane] except (KeyError, TypeError): raise ValueError('{} is not a valid plane'.format(plane)) - - if isinstance(center_to, string_types): - if not center_to == 'center': - raise ValueError('{} is not a valid "center_to"'.format(center_to)) - else: - center_to = np.asarray(center_to, np.float32) - if center_to.shape != (3, ) and center_to.shape != (1, 3): - raise ValueError('{} is not a valid "center_to"'.format(center_to)) - else: + try: + if center_to != "center": + center_to = np.asarray(center_to, np.float32) + if center_to.shape != (3, ) and center_to.shape != (1, 3): + raise ValueError('{} is not a valid "center_to"'.format(center_to)) center_to = center_to.reshape(3, ) + except ValueError: + raise ValueError('{} is not a valid "center_to"'.format(center_to)) try: atoms = ag.atoms except AttributeError: @@ -296,17 +294,14 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): axis = axes[axis] except (KeyError, TypeError): raise ValueError('{} is not a valid axis'.format(axis)) - if isinstance(center_to, string_types): - if center_to != 'center': - raise ValueError('{} is not a valid "center_to"'.format(center_to)) - else: - try: + try: + if center_to != "center": center_to = np.asarray(center_to, np.float32) if center_to.shape != (3, ) and center_to.shape != (1, 3): raise ValueError('{} is not a valid "center_to"'.format(center_to)) center_to = center_to.reshape(3, ) - except ValueError: - raise ValueError('{} is not a valid "center_to"'.format(center_to)) + except ValueError: + raise ValueError('{} is not a valid "center_to"'.format(center_to)) try: atoms = ag.atoms except AttributeError: From 561f5dbeb2d87f97255b339a80eca4a199e0717c Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Mon, 23 Jul 2018 15:49:01 +0100 Subject: [PATCH 12/16] removed deprecated imports --- package/MDAnalysis/transformations/translate.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 066eb8dbde1..cd50c92f8ac 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -33,8 +33,6 @@ from __future__ import absolute_import, division import numpy as np -from numbers import Number -from six import string_types from functools import partial from ..lib.mdamath import triclinic_vectors From f7bce749be32a1d49467cc4ab7cf428b5f92bca4 Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Sat, 28 Jul 2018 17:37:19 +0100 Subject: [PATCH 13/16] updated docs --- .../MDAnalysis/transformations/translate.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index cd50c92f8ac..bb092161366 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -24,10 +24,19 @@ Trajectory translation --- :mod:`MDAnalysis.transformations.translate` ====================================================================== -Translate the coordinates of a given trajectory by a given vector. -The vector can either be user defined, using the function :func:`translate` -or defined by centering an AtomGroup in the unit cell using the function -:func:`center_in_box` +Translate the coordinates of a given trajectory. Coordinates may be +translated by a vector, using the function :func:`translate` or defined +by centering an AtomGroup in the unit cell, a plane or axis using the functions +:func:`center_in_box`, :func:`center_in_plane` or :func:`center_in_axis`, +respectively. + +.. autofunction:: translate + +.. autofunction:: center_in_box + +.. autofunction:: center_in_plane + +.. autofunction:: center_in_axis """ from __future__ import absolute_import, division @@ -46,9 +55,9 @@ def translate(vector): Example ------- - Translate the coordinates of the system by the [1, 2, 3] vector + Translate the coordinates of the system by the [1, 2, 3] vector: - ..code-block:: python + .. code-block:: python transform = mda.transformations.translate([1,2,3]) u.trajectory.add_transformations(transform) @@ -256,7 +265,8 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): .. code-block:: python ag = u.residues[1].atoms - transform = mda.transformations.center_in_axis(ag, 'x', [0,0,1], center_of='mass') + transform = mda.transformations.center_in_axis(ag, 'x', [0,0,1], + weights='mass') u.trajectory.add_transformation(transform) Parameters From 12a5bd9cf6c23182edb7d74e62efeac20236bb81 Mon Sep 17 00:00:00 2001 From: Davide Cruz <37750297+davidercruz@users.noreply.github.com> Date: Wed, 1 Aug 2018 19:25:28 +0100 Subject: [PATCH 14/16] typo in center_in_box docs --- package/MDAnalysis/transformations/translate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index bb092161366..55cb730419a 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -114,7 +114,7 @@ def center_in_box(ag, weights=None, center_to=None, wrap=False): If a float array of the same length as `ag` is provided, use each element of the `array_like` as a weight for the corresponding atom in `ag`. Default is None. - point: array-like, optional + center_to: array-like, optional overrides the unit cell center - the coordinates of the Timestep are translated so that the center of mass/geometry of the given AtomGroup is aligned to this position instead. Defined as an array of size 3. From c0ee82eef3da85d73581de40a699165db7e2ded8 Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Thu, 2 Aug 2018 12:18:52 +0100 Subject: [PATCH 15/16] added unwrap option to all functions --- .../MDAnalysis/transformations/translate.py | 55 +++-- .../transformations/test_translate.py | 191 ++++++++++++++++-- 2 files changed, 213 insertions(+), 33 deletions(-) diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 55cb730419a..a680adbc677 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -46,6 +46,7 @@ from ..lib.mdamath import triclinic_vectors from ..lib.util import get_weights +from ..lib._cutil import make_whole def translate(vector): """ @@ -85,7 +86,7 @@ def wrapped(ts): return wrapped -def center_in_box(ag, weights=None, center_to=None, wrap=False): +def center_in_box(ag, weights=None, center_to=None, wrap=False, unwrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -101,7 +102,7 @@ def center_in_box(ag, weights=None, center_to=None, wrap=False): .. code-block:: python ag = u.residues[1].atoms - transform = mda.transformations.center(ag, center_of='mass') + transform = mda.transformations.center(ag, weights='mass') u.trajectory.add_transformations(transform) Parameters @@ -120,8 +121,13 @@ def center_in_box(ag, weights=None, center_to=None, wrap=False): instead. Defined as an array of size 3. wrap: bool, optional If `True`, all the atoms from the given AtomGroup will be moved to the unit cell - before calculating the center of mass or geometry. Default is `False`, no changes - to the atom coordinates are done before calculating the center of the AtomGroup. + before calculating the weighted center. Default is `False`, no changes to the atom + coordinates are done before calculating the center of the AtomGroup. + unwrap: bool, optional + If `True`, all the atoms from the given AtomGroup will be moved so as to not break + any bonds over periodic boundaries before calculating the weighted center. Default + is `False`, no changes to the atom coordinates are done before calculating the center + of the AtomGroup. Returns ------- @@ -146,14 +152,17 @@ def center_in_box(ag, weights=None, center_to=None, wrap=False): except (ValueError, TypeError): raise TypeError("weights must be {'mass', None} or an iterable of the " "same size as the atomgroup.") - center_method = partial(atoms.center, weights, pbc=wrap) - + if unwrap and wrap: + raise ValueError("wrap and unwrap can't be both True") + center_method = partial(atoms.center, weights, pbc=wrap) + def wrapped(ts): if center_to is None: boxcenter = np.sum(ts.triclinic_dimensions, axis=0) / 2 else: boxcenter = center_to - + if unwrap: + make_whole(ag) ag_center = center_method() vector = boxcenter - ag_center @@ -164,7 +173,7 @@ def wrapped(ts): return wrapped -def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): +def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False, unwrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -201,8 +210,13 @@ def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): None. wrap: bool, optional If `True`, all the atoms from the given AtomGroup will be moved to the unit cell - before calculating the center of mass or geometry. Default is `False`, no changes - to the atom coordinates are done before calculating the center of the AtomGroup. + before calculating the weighted center. Default is `False`, no changes to the atom + coordinates are done before calculating the center of the AtomGroup. + unwrap: bool, optional + If `True`, all the atoms from the given AtomGroup will be moved so as to not break + any bonds over periodic boundaries before calculating the weighted center. Default + is `False`, no changes to the atom coordinates are done before calculating the center + of the AtomGroup. Returns ------- @@ -232,6 +246,8 @@ def center_in_plane(ag, plane, center_to="center", weights=None, wrap=False): except (ValueError, TypeError): raise TypeError("weights must be {'mass', None} or an iterable of the " "same size as the atomgroup.") + if unwrap and wrap: + raise ValueError("wrap and unwrap can't be both True") center_method = partial(atoms.center, weights, pbc=wrap) def wrapped(ts): @@ -240,6 +256,8 @@ def wrapped(ts): _origin = boxcenter else: _origin = center_to + if unwrap: + make_whole(ag) position = center_method() position[plane] = _origin[plane] vector = np.asarray(position, np.float32) - center_method() @@ -250,7 +268,7 @@ def wrapped(ts): return wrapped -def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): +def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False, unwrap=False): """ Translates the coordinates of a given :class:`~MDAnalysis.coordinates.base.Timestep` instance so that the center of geometry/mass of the given :class:`~MDAnalysis.core.groups.AtomGroup` @@ -289,9 +307,14 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): None. wrap: bool, optional If `True`, all the atoms from the given AtomGroup will be moved to the unit cell - before calculating the center of mass or geometry. Default is `False`, no changes - to the atom coordinates are done before calculating the center of the AtomGroup. - + before calculating the weighted center. Default is `False`, no changes to the atom + coordinates are done before calculating the center of the AtomGroup. + unwrap: bool, optional + If `True`, all the atoms from the given AtomGroup will be moved so as to not break + any bonds over periodic boundaries before calculating the weighted center. Default + is `False`, no changes to the atom coordinates are done before calculating the center + of the AtomGroup. + Returns ------- MDAnalysis.coordinates.base.Timestep @@ -320,6 +343,8 @@ def center_in_axis(ag, axis, center_to="center", weights=None, wrap=False): except (ValueError, TypeError): raise TypeError("weights must be {'mass', None} or an iterable of the " "same size as the atomgroup.") + if unwrap and wrap: + raise ValueError("wrap and unwrap can't be both True") center_method = partial(ag.atoms.center, weights, pbc=wrap) def wrapped(ts): @@ -327,6 +352,8 @@ def wrapped(ts): _origin = ts.triclinic_dimensions.sum(axis=0) / 2.0 else: _origin = center_to + if unwrap: + make_whole(ag) ag_center = center_method() center = _origin center[axis] = ag_center[axis] diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 02b451253cc..878fc52535b 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -29,6 +29,7 @@ import MDAnalysis as mda from MDAnalysis.transformations import translate, center_in_box, center_in_plane, center_in_axis from MDAnalysisTests import make_Universe +from MDAnalysisTests.datafiles import fullerene @pytest.fixture() @@ -42,6 +43,18 @@ def translate_universes(): return reference, transformed +@pytest.fixture() +def translate_unwrap_universes(): + # create the Universe objects for the tests + # this universe is used for the unwrap testing cases + reference = mda.Universe(fullerene) + transformed = mda.Universe(fullerene) + transformed.dimensions = np.asarray([10, 10, 10, 90, 90, 90], np.float32) + transformed.atoms.wrap() + + return reference, transformed + + def test_translate_coords(translate_universes): ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts @@ -123,16 +136,35 @@ def test_center_in_box_bad_center_to(translate_universes, center_to): center_in_box(ag, center_to=bad_center_to)(ts) -def test_center_in_box_bad_pbc(translate_universes): +def test_center_in_box_bad_wrap(translate_universes): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms - # is pbc passed to the center methods? + # is wrap passed to the center methods? # if yes it should raise an exception for boxes that are zero in size with pytest.raises(ValueError): center_in_box(ag, wrap=True)(ts) +def test_center_in_box_bad_unwrap(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # is wrap passed to the center methods? + # if yes it should raise an exception for boxes that are zero in size + with pytest.raises(ValueError): + center_in_box(ag, unwrap=True)(ts) + + +def test_center_in_box_bad_wrap_unwrap(translate_universes): + # this universe has a box size zero + ts = translate_universes[1].trajectory.ts + ag = translate_universes[1].residues[0].atoms + # the two options are not compatible so it should throw an error + with pytest.raises(ValueError): + center_in_box(ag, wrap=True, unwrap=True)(ts) + + @pytest.mark.parametrize('weights', ( " ", "totallynotmasses", @@ -182,7 +214,7 @@ def test_center_in_box_coords_no_options(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_box_coords_with_pbc(translate_universes): +def test_center_in_box_coords_with_wrap(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? # using pbc into account for center of geometry calculation ref_u, trans_u = translate_universes @@ -196,13 +228,26 @@ def test_center_in_box_coords_with_pbc(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) +def test_center_in_box_coords_with_unwrap(translate_unwrap_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_unwrap_universes + ref = ref_u.trajectory.ts + ag = trans_u.atoms + box_center = np.float32([5, 5, 5]) + ref_center = ref_u.atoms.center(weights=None) + ref.positions += box_center - ref_center + trans = center_in_box(ag, unwrap=True)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + def test_center_in_box_coords_with_mass(translate_universes): # using masses for calculating the center of the atomgroup ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[24].atoms box_center = np.float32([186., 186.5, 187.]) - ref_center = ag.center_of_mass() + ref_center = ag.center(weights=ag.masses) ref.positions += box_center - ref_center trans = center_in_box(ag, weights="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) @@ -221,7 +266,7 @@ def test_center_in_box_coords_with_box(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_box_coords_all_options(translate_universes): +def test_center_in_box_coords_all_options_wrap(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? # using pbc into account for center of geometry calculation ref_u, trans_u = translate_universes @@ -229,12 +274,26 @@ def test_center_in_box_coords_all_options(translate_universes): ag = trans_u.residues[24].atoms newpoint = [1000, 1000, 1000] box_center = np.float32(newpoint) - ref_center = ag.center_of_mass(pbc=True) + ref_center = ag.center(weights=ag.masses, pbc=True) ref.positions += box_center - ref_center trans = center_in_box(ag, weights='mass', wrap=True, center_to=newpoint)(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) +def test_center_in_box_coords_all_options_unwrap(translate_unwrap_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_unwrap_universes + ref = ref_u.trajectory.ts + ag = trans_u.atoms + newpoint = [1000, 1000, 1000] + box_center = np.float32(newpoint) + ref_center = ref_u.atoms.center(weights=ref_u.atoms.masses) + ref.positions += box_center - ref_center + trans = center_in_box(ag, weights='mass', unwrap=True, center_to=newpoint)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + @pytest.mark.parametrize('ag', ( [0, 1], [0, 1, 2, 3, 4], @@ -291,17 +350,38 @@ def test_center_in_axis_bad_axis(translate_universes, axis): center_in_axis(ag, bad_axis)(ts) -def test_center_in_axis_bad_pbc(translate_universes): +def test_center_in_axis_bad_wrap(translate_universes): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms - # is pbc passed to the center methods? + # is wrap passed to the center methods? # if yes it should raise an exception for boxes that are zero in size axis = 'x' with pytest.raises(ValueError): center_in_axis(ag,axis, wrap=True)(ts) +def test_center_in_axis_bad_unwrap(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # is unwrap passed to the center methods? + # if yes it should raise an exception for boxes that are zero in size + axis = 'x' + with pytest.raises(ValueError): + center_in_axis(ag,axis, unwrap=True)(ts) + + +def test_center_in_axis_bad_wrap_unwrap(translate_universes): + # this universe has a box size zero + ts = translate_universes[1].trajectory.ts + ag = translate_universes[1].residues[0].atoms + # the two options are not compatible so it should throw an error + axis = 'x' + with pytest.raises(ValueError): + center_in_axis(ag,axis, wrap=True, unwrap=True)(ts) + + @pytest.mark.parametrize('weights', ( " ", "totallynotmasses", @@ -356,7 +436,7 @@ def test_center_in_axis_coords_no_options(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_axis_coords_with_pbc(translate_universes): +def test_center_in_axis_coords_with_wrap(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue # taking pbc into account for center of geometry calculation? ref_u, trans_u = translate_universes @@ -373,12 +453,28 @@ def test_center_in_axis_coords_with_pbc(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) +def test_center_in_axis_coords_with_unwrap(translate_unwrap_universes): + # what happens when we center the coordinates arround the center of geometry of a residue + # taking pbc into account for center of geometry calculation? + ref_u, trans_u = translate_unwrap_universes + ref = ref_u.trajectory.ts + ag = trans_u.atoms + box_center = np.float32([5, 5, 5]) + center_to = box_center + ref_center = ref_u.atoms.center(weights=None) + axis = 'x' + axis_point = np.float32([ref_center[0], center_to[1], center_to[2]]) + ref.positions += axis_point - ref_center + trans = center_in_axis(ag, axis, unwrap=True)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + def test_center_in_axis_coords_with_mass(translate_universes): # using masses for calculating the center of the atomgroup ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[24].atoms - ref_center = ag.center_of_mass() + ref_center = ag.center(weights=ag.masses) box_center = np.float32([186., 186.5, 187.]) center_to = box_center axis = 'x' @@ -402,14 +498,14 @@ def test_center_in_axis_coords_with_coord_center_to(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_axis_coords_all_options(translate_universes): +def test_center_in_axis_coords_all_options_wrap(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? # using pbc into account for center of geometry calculation ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[24].atoms neworigin = [1000, 1000, 1000] - ref_center = ag.center_of_mass(pbc=True) + ref_center = ag.center(weights=ag.masses, pbc=True) axis = 'x' axis_point = np.float32([ref_center[0], neworigin[1], neworigin[2]]) ref.positions += axis_point - ref_center @@ -417,6 +513,21 @@ def test_center_in_axis_coords_all_options(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) +def test_center_in_axis_coords_all_options_unwrap(translate_unwrap_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_unwrap_universes + ref = ref_u.trajectory.ts + ag = trans_u.atoms + neworigin = [1000, 1000, 1000] + ref_center = ref_u.atoms.center(weights=ref_u.atoms.masses) + axis = 'x' + axis_point = np.float32([ref_center[0], neworigin[1], neworigin[2]]) + ref.positions += axis_point - ref_center + trans = center_in_axis(ag, axis, weights='mass', unwrap=True, center_to=neworigin)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + @pytest.mark.parametrize('ag', ( [0, 1], [0, 1, 2, 3, 4], @@ -473,17 +584,28 @@ def test_center_in_plane_bad_plane(translate_universes, plane): center_in_plane(ag, bad_plane)(ts) -def test_center_in_plane_bad_pbc(translate_universes): +def test_center_in_plane_bad_wrap(translate_universes): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms - # is pbc passed to the center methods? + # is wrap passed to the center methods? # if yes it should raise an exception for boxes that are zero in size plane = 'yz' with pytest.raises(ValueError): center_in_plane(ag, plane, wrap=True)(ts) +def test_center_in_plane_bad_unwrap(translate_universes): + # this universe has a box size zero + ts = translate_universes[0].trajectory.ts + ag = translate_universes[0].residues[0].atoms + # is unwrap passed to the center methods? + # if yes it should raise an exception for boxes that are zero in size + plane = 'yz' + with pytest.raises(ValueError): + center_in_plane(ag, plane, unwrap=True)(ts) + + def test_center_in_plane_bad_weights(translate_universes): # this universe has a box size zero ts = translate_universes[0].trajectory.ts @@ -528,7 +650,7 @@ def test_center_in_plane_coords_no_options(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_plane_coords_with_pbc(translate_universes): +def test_center_in_plane_coords_with_wrap(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? # using pbc into account for center of geometry calculation ref_u, trans_u = translate_universes @@ -536,7 +658,7 @@ def test_center_in_plane_coords_with_pbc(translate_universes): trans_u.dimensions = [363., 364., 365., 90., 90., 90.] box_center = np.float32([181.5, 182., 182.5]) ag = trans_u.residues[24].atoms - ref_center = ag.center_of_geometry(pbc=True) + ref_center = ag.center(weights=None, pbc=True) plane = 'yz' plane_point = np.asarray([box_center[0], ref_center[1], ref_center[2]], np.float32) ref.positions += plane_point - ref_center @@ -544,13 +666,28 @@ def test_center_in_plane_coords_with_pbc(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) +def test_center_in_plane_coords_with_unwrap(translate_unwrap_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_unwrap_universes + ref = ref_u.trajectory.ts + box_center = np.float32([5, 5, 5]) + ag = trans_u.atoms + ref_center = ref_u.atoms.center(weights=None) + plane = 'yz' + plane_point = np.asarray([box_center[0], ref_center[1], ref_center[2]], np.float32) + ref.positions += plane_point - ref_center + trans = center_in_plane(ag, plane, unwrap=True)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + def test_center_in_plane_coords_with_mass(translate_universes): # using masses for calculating the center of the atomgroup ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts ag = trans_u.residues[24].atoms box_center = np.float32([186., 186.5, 187.]) - ref_center = ag.center_of_mass() + ref_center = ag.center(weights=ag.masses) plane = 'yz' plane_point = np.asarray([box_center[0], ref_center[1], ref_center[2]], np.float32) ref.positions += plane_point - ref_center @@ -573,7 +710,7 @@ def test_center_in_plane_coords_with_coord_center_to(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_plane_coords_all_options(translate_universes): +def test_center_in_plane_coords_all_options_wrap(translate_universes): # what happens when we center the coordinates arround the center of geometry of a residue? # using pbc into account for center of geometry calculation ref_u, trans_u = translate_universes @@ -582,7 +719,7 @@ def test_center_in_plane_coords_all_options(translate_universes): trans_u.dimensions = [363., 364., 365., 90., 90., 90.] box_center = np.float32([181.5, 182., 182.5]) center_to = [1000, 1000, 1000] - ref_center = ag.center_of_mass(pbc=True) + ref_center = ag.center(weights=ag.masses, pbc=True) plane = 'yz' plane_point = np.float32([center_to[0], ref_center[1], ref_center[2]]) ref.positions += plane_point - ref_center @@ -590,6 +727,22 @@ def test_center_in_plane_coords_all_options(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) +def test_center_in_plane_coords_all_options_unwrap(translate_unwrap_universes): + # what happens when we center the coordinates arround the center of geometry of a residue? + # using pbc into account for center of geometry calculation + ref_u, trans_u = translate_unwrap_universes + ref = ref_u.trajectory.ts + ag = trans_u.atoms + box_center = np.float32([5, 5, 5]) + center_to = [1000, 1000, 1000] + ref_center = ref_u.atoms.center(weights=ref_u.atoms.masses) + plane = 'yz' + plane_point = np.float32([center_to[0], ref_center[1], ref_center[2]]) + ref.positions += plane_point - ref_center + trans = center_in_plane(ag, plane, center_to=center_to, weights='mass', unwrap=True)(trans_u.trajectory.ts) + assert_array_almost_equal(trans.positions, ref.positions, decimal=6) + + def test_center_in_box_transformations_api(translate_universes): # test if the translate transformation works when using the # on-the-fly transformations API From 9f9d8d92b3bbd51fd817b014a516651d8163f58d Mon Sep 17 00:00:00 2001 From: Davide Cruz Date: Fri, 3 Aug 2018 18:52:56 +0100 Subject: [PATCH 16/16] updated tests --- .../transformations/test_translate.py | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 878fc52535b..e20e5c6f90f 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -169,9 +169,8 @@ def test_center_in_box_bad_wrap_unwrap(translate_universes): " ", "totallynotmasses", 123456789, - [0, 1, 2, 3, 4], np.array([0, 1]), - np.array([0, 1, 2, 3, 4]), + np.array([0, 1, 2, 3]), np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])) ) def test_center_in_box_bad_weights(translate_universes, weights): @@ -179,9 +178,8 @@ def test_center_in_box_bad_weights(translate_universes, weights): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? - bad_weights = " " with pytest.raises(TypeError): - center_in_box(ag, weights=bad_weights)(ts) + center_in_box(ag, weights=weights)(ts) def test_center_in_box_no_masses(translate_universes): @@ -386,9 +384,8 @@ def test_center_in_axis_bad_wrap_unwrap(translate_universes): " ", "totallynotmasses", 123456789, - [0, 1, 2, 3, 4], np.array([0, 1]), - np.array([0, 1, 2, 3, 4]), + np.array([0, 1, 2, 3]), np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])) ) def test_center_in_axis_bad_weights(translate_universes, weights): @@ -396,10 +393,9 @@ def test_center_in_axis_bad_weights(translate_universes, weights): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? - bad_weights = " " axis = 'x' with pytest.raises(TypeError): - center_in_axis(ag, axis, weights=bad_weights)(ts) + center_in_axis(ag, axis, weights=weights)(ts) def test_center_in_axis_no_masses(translate_universes): @@ -606,15 +602,22 @@ def test_center_in_plane_bad_unwrap(translate_universes): center_in_plane(ag, plane, unwrap=True)(ts) -def test_center_in_plane_bad_weights(translate_universes): +@pytest.mark.parametrize('weights', ( + " ", + "totallynotmasses", + 123456789, + np.array([0, 1]), + np.array([0, 1, 2, 3]), + np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])) +) +def test_center_in_plane_bad_weights(translate_universes, weights): # this universe has a box size zero ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? - bad_weights = " " plane = 'yz' with pytest.raises(TypeError): - center_in_plane(ag, plane, weights=bad_weights)(ts) + center_in_plane(ag, plane, weights=weights)(ts) def test_center_in_planes_no_masses(translate_universes):