diff --git a/package/MDAnalysis/transformations/base.py b/package/MDAnalysis/transformations/base.py index 59ad37e7fa..ab0f6ea899 100644 --- a/package/MDAnalysis/transformations/base.py +++ b/package/MDAnalysis/transformations/base.py @@ -104,8 +104,8 @@ def __init__(self, **kwargs): analysis approach. Default is ``True``. """ - self.max_threads = kwargs.pop('max_threads', None) - self.parallelizable = kwargs.pop('parallelizable', True) + self.max_threads = kwargs.pop("max_threads", None) + self.parallelizable = kwargs.pop("parallelizable", True) def __call__(self, ts): """The function that makes transformation can be called as a function diff --git a/package/MDAnalysis/transformations/boxdimensions.py b/package/MDAnalysis/transformations/boxdimensions.py index 0f5ebbd322..c18cdc36a7 100644 --- a/package/MDAnalysis/transformations/boxdimensions.py +++ b/package/MDAnalysis/transformations/boxdimensions.py @@ -34,6 +34,7 @@ from .base import TransformationBase + class set_dimensions(TransformationBase): """ Set simulation box dimensions. @@ -85,33 +86,31 @@ class set_dimensions(TransformationBase): Added the option to set varying box dimensions (i.e. an NPT trajectory). """ - def __init__(self, - dimensions, - max_threads=None, - parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + def __init__(self, dimensions, max_threads=None, parallelizable=True): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.dimensions = dimensions try: self.dimensions = np.asarray(self.dimensions, np.float32) except ValueError: errmsg = ( - f'{self.dimensions} cannot be converted into ' - 'np.float32 numpy.ndarray' + f"{self.dimensions} cannot be converted into " + "np.float32 numpy.ndarray" ) raise ValueError(errmsg) try: self.dimensions = self.dimensions.reshape(-1, 6) except ValueError: errmsg = ( - f'{self.dimensions} array does not have valid box ' - 'dimension shape.\nSimulation box dimensions are ' - 'given by an float array of shape (6, 0), (1, 6), ' - 'or (N, 6) where N is the number of frames in the ' - 'trajectory and the dimension vector(s) containing ' - '3 lengths and 3 angles: ' - '[a, b, c, alpha, beta, gamma]' + f"{self.dimensions} array does not have valid box " + "dimension shape.\nSimulation box dimensions are " + "given by an float array of shape (6, 0), (1, 6), " + "or (N, 6) where N is the number of frames in the " + "trajectory and the dimension vector(s) containing " + "3 lengths and 3 angles: " + "[a, b, c, alpha, beta, gamma]" ) raise ValueError(errmsg) diff --git a/package/MDAnalysis/transformations/fit.py b/package/MDAnalysis/transformations/fit.py index 2356201c54..89336128cb 100644 --- a/package/MDAnalysis/transformations/fit.py +++ b/package/MDAnalysis/transformations/fit.py @@ -90,10 +90,19 @@ class fit_translation(TransformationBase): The transformation was changed to inherit from the base class for limiting threads and checking if it can be used in parallel analysis. """ - def __init__(self, ag, reference, plane=None, weights=None, - max_threads=None, parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + + def __init__( + self, + ag, + reference, + plane=None, + weights=None, + max_threads=None, + parallelizable=True, + ): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag self.reference = reference @@ -101,34 +110,37 @@ def __init__(self, ag, reference, plane=None, weights=None, self.weights = weights if self.plane is not None: - axes = {'yz': 0, 'xz': 1, 'xy': 2} + axes = {"yz": 0, "xz": 1, "xy": 2} try: self.plane = axes[self.plane] except (TypeError, KeyError): - raise ValueError(f'{self.plane} is not a valid plane') \ - from None + raise ValueError( + f"{self.plane} is not a valid plane" + ) from None try: if self.ag.atoms.n_residues != self.reference.atoms.n_residues: errmsg = ( - f"{self.ag} and {self.reference} have mismatched" - f"number of residues" + f"{self.ag} and {self.reference} have mismatched" + f"number of residues" ) raise ValueError(errmsg) except AttributeError: errmsg = ( - f"{self.ag} or {self.reference} is not valid" - f"Universe/AtomGroup" + f"{self.ag} or {self.reference} is not valid" + f"Universe/AtomGroup" ) raise AttributeError(errmsg) from None - self.ref, self.mobile = align.get_matching_atoms(self.reference.atoms, - self.ag.atoms) + self.ref, self.mobile = align.get_matching_atoms( + self.reference.atoms, self.ag.atoms + ) self.weights = align.get_weights(self.ref.atoms, weights=self.weights) self.ref_com = self.ref.center(self.weights) def _transform(self, ts): - mobile_com = np.asarray(self.mobile.atoms.center(self.weights), - np.float32) + mobile_com = np.asarray( + self.mobile.atoms.center(self.weights), np.float32 + ) vector = self.ref_com - mobile_com if self.plane is not None: vector[self.plane] = 0 @@ -197,10 +209,19 @@ class fit_rot_trans(TransformationBase): The transformation was changed to inherit from the base class for limiting threads and checking if it can be used in parallel analysis. """ - def __init__(self, ag, reference, plane=None, weights=None, - max_threads=1, parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + + def __init__( + self, + ag, + reference, + plane=None, + weights=None, + max_threads=1, + parallelizable=True, + ): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag self.reference = reference @@ -208,12 +229,13 @@ def __init__(self, ag, reference, plane=None, weights=None, self.weights = weights if self.plane is not None: - axes = {'yz': 0, 'xz': 1, 'xy': 2} + axes = {"yz": 0, "xz": 1, "xy": 2} try: self.plane = axes[self.plane] except (TypeError, KeyError): - raise ValueError(f'{self.plane} is not a valid plane') \ - from None + raise ValueError( + f"{self.plane} is not a valid plane" + ) from None try: if self.ag.atoms.n_residues != self.reference.atoms.n_residues: errmsg = ( @@ -223,12 +245,13 @@ def __init__(self, ag, reference, plane=None, weights=None, raise ValueError(errmsg) except AttributeError: errmsg = ( - f"{self.ag} or {self.reference} is not valid " - f"Universe/AtomGroup" + f"{self.ag} or {self.reference} is not valid " + f"Universe/AtomGroup" ) raise AttributeError(errmsg) from None - self.ref, self.mobile = align.get_matching_atoms(self.reference.atoms, - self.ag.atoms) + self.ref, self.mobile = align.get_matching_atoms( + self.reference.atoms, self.ag.atoms + ) self.weights = align.get_weights(self.ref.atoms, weights=self.weights) self.ref_com = self.ref.center(self.weights) self.ref_coordinates = self.ref.atoms.positions - self.ref_com @@ -236,22 +259,23 @@ def __init__(self, ag, reference, plane=None, weights=None, def _transform(self, ts): mobile_com = self.mobile.atoms.center(self.weights) mobile_coordinates = self.mobile.atoms.positions - mobile_com - rotation, dump = align.rotation_matrix(mobile_coordinates, - self.ref_coordinates, - weights=self.weights) + rotation, dump = align.rotation_matrix( + mobile_coordinates, self.ref_coordinates, weights=self.weights + ) vector = self.ref_com if self.plane is not None: matrix = np.r_[rotation, np.zeros(3).reshape(1, 3)] matrix = np.c_[matrix, np.zeros(4)] - euler_angs = np.asarray(euler_from_matrix(matrix, axes='sxyz'), - np.float32) + euler_angs = np.asarray( + euler_from_matrix(matrix, axes="sxyz"), np.float32 + ) for i in range(0, euler_angs.size): - euler_angs[i] = (euler_angs[self.plane] if i == self.plane - else 0) - rotation = euler_matrix(euler_angs[0], - euler_angs[1], - euler_angs[2], - axes='sxyz')[:3, :3] + euler_angs[i] = ( + euler_angs[self.plane] if i == self.plane else 0 + ) + rotation = euler_matrix( + euler_angs[0], euler_angs[1], euler_angs[2], axes="sxyz" + )[:3, :3] vector[self.plane] = mobile_com[self.plane] ts.positions = ts.positions - mobile_com ts.positions = np.dot(ts.positions, rotation.T) diff --git a/package/MDAnalysis/transformations/nojump.py b/package/MDAnalysis/transformations/nojump.py index fd6dc7703e..d4a54f6f8d 100644 --- a/package/MDAnalysis/transformations/nojump.py +++ b/package/MDAnalysis/transformations/nojump.py @@ -50,7 +50,7 @@ class NoJump(TransformationBase): across periodic boundary edges. The algorithm used is based on :footcite:p:`Kulke2022`, equation B6 for non-orthogonal systems, so it is general to most applications where molecule trajectories should not "jump" from one side of a periodic box to another. - + Note that this transformation depends on a periodic box dimension being set for every frame in the trajectory, and that this box dimension can be transformed to an orthonormal unit cell. If not, an error is emitted. Since it is typical to transform all frames @@ -133,7 +133,8 @@ def _transform(self, ts): if ( self.check_c and self.older_frame != "A" - and (self.old_frame - self.older_frame) != (ts.frame - self.old_frame) + and (self.old_frame - self.older_frame) + != (ts.frame - self.old_frame) ): warnings.warn( "NoJump detected that the interval between frames is unequal." @@ -155,7 +156,9 @@ def _transform(self, ts): ) # Convert into reduced coordinate space fcurrent = ts.positions @ Linverse - fprev = self.prev # Previous unwrapped coordinates in reduced box coordinates. + fprev = ( + self.prev + ) # Previous unwrapped coordinates in reduced box coordinates. # Calculate the new positions in reduced coordinate space (Equation B6 from # 10.1021/acs.jctc.2c00327). As it turns out, the displacement term can # be moved inside the round function in this coordinate space, as the @@ -164,7 +167,9 @@ def _transform(self, ts): # Convert back into real space ts.positions = newpositions @ L # Set things we need to save for the next frame. - self.prev = newpositions # Note that this is in reduced coordinate space. + self.prev = ( + newpositions # Note that this is in reduced coordinate space. + ) self.older_frame = self.old_frame self.old_frame = ts.frame diff --git a/package/MDAnalysis/transformations/positionaveraging.py b/package/MDAnalysis/transformations/positionaveraging.py index 13145b69c4..d091dd9bbf 100644 --- a/package/MDAnalysis/transformations/positionaveraging.py +++ b/package/MDAnalysis/transformations/positionaveraging.py @@ -42,9 +42,9 @@ class PositionAverager(TransformationBase): """ Averages the coordinates of a given timestep so that the coordinates of the AtomGroup correspond to the average positions of the N previous - frames. + frames. For frames < N, the average of the frames iterated up to that point will - be returned. + be returned. Example ------- @@ -59,7 +59,7 @@ class PositionAverager(TransformationBase): N=3 transformation = PositionAverager(N, check_reset=True) - u.trajectory.add_transformations(transformation) + u.trajectory.add_transformations(transformation) for ts in u.trajectory: print(ts.positions) @@ -72,18 +72,18 @@ class PositionAverager(TransformationBase): manually reset before restarting an iteration. In this case, ``ts.positions`` will return the average coordinates of the last N iterated frames, despite them not being sequential - (``frames = [0, 7, 1, 6]``). + (``frames = [0, 7, 1, 6]``). .. code-block:: python - + N=3 transformation = PositionAverager(N, check_reset=False) u.trajectory.add_transformations(transformation) - frames = [0, 7, 1, 6] + frames = [0, 7, 1, 6] transformation.resetarrays() for ts in u.trajectory[frames]: print(ts.positions) - + If ``check_reset=True``, the ``PositionAverager`` would have automatically reset after detecting a non sequential iteration (i.e. when iterating from frame 7 to frame 1 or when resetting the iterator from frame 6 back to @@ -98,14 +98,14 @@ class PositionAverager(TransformationBase): these examples corresponds to ``N=3``. .. code-block:: python - + N=3 transformation = PositionAverager(N, check_reset=True) - u.trajectory.add_transformations(transformation) + u.trajectory.add_transformations(transformation) for ts in u.trajectory: if transformation.current_avg == transformation.avg_frames: print(ts.positions) - + In the case of ``N=3``, as the average is calculated with the frames iterated up to the current iteration, the first frame returned will not be averaged. During the first iteration no other frames are stored in @@ -115,21 +115,21 @@ class PositionAverager(TransformationBase): following iterations will ``ts.positions`` start returning the average of the last 3 frames and thus ``transformation.current_avg = 3`` These initial frames are typically not desired during analysis, but one can - easily avoid them, as seen in the previous example with + easily avoid them, as seen in the previous example with ``if transformation.current_avg == transformation.avg_frames:`` or by - simply removing the first ``avg_frames-1`` frames from the analysis. + simply removing the first ``avg_frames-1`` frames from the analysis. Parameters ---------- avg_frames: int - Determines the number of frames to be used for the position averaging. + Determines the number of frames to be used for the position averaging. check_reset: bool, optional If ``True``, position averaging will be reset and a warning raised when the trajectory iteration direction changes. If ``False``, position averaging will not reset, regardless of the iteration. - + Returns ------- @@ -141,11 +141,16 @@ class PositionAverager(TransformationBase): limiting threads and checking if it can be used in parallel analysis. """ - def __init__(self, avg_frames, check_reset=True, - max_threads=None, - parallelizable=False): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + def __init__( + self, + avg_frames, + check_reset=True, + max_threads=None, + parallelizable=False, + ): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.avg_frames = avg_frames self.check_reset = check_reset self.current_avg = 0 @@ -164,8 +169,11 @@ def rollposx(self, ts): try: self.coord_array.size except AttributeError: - size = (ts.positions.shape[0], ts.positions.shape[1], - self.avg_frames) + size = ( + ts.positions.shape[0], + ts.positions.shape[1], + self.avg_frames, + ) self.coord_array = np.empty(size) self.coord_array = np.roll(self.coord_array, 1, axis=2) @@ -175,9 +183,11 @@ def _transform(self, ts): # calling the same timestep will not add new data to coord_array # This can prevent from getting different values when # call `u.trajectory[i]` multiple times. - if (ts.frame == self.current_frame - and hasattr(self, 'coord_array') - and not np.isnan(self.idx_array).all()): + if ( + ts.frame == self.current_frame + and hasattr(self, "coord_array") + and not np.isnan(self.idx_array).all() + ): test = ~np.isnan(self.idx_array) ts.positions = np.mean(self.coord_array[..., test], axis=2) return ts @@ -190,9 +200,11 @@ def _transform(self, ts): if self.check_reset: sign = np.sign(np.diff(self.idx_array[test])) if not (np.all(sign == 1) or np.all(sign == -1)): - warnings.warn('Cannot average position for non sequential' - 'iterations. Averager will be reset.', - Warning) + warnings.warn( + "Cannot average position for non sequential" + "iterations. Averager will be reset.", + Warning, + ) self.resetarrays() return self(ts) diff --git a/package/MDAnalysis/transformations/rotate.py b/package/MDAnalysis/transformations/rotate.py index ddb730f069..4d8fa71d0b 100644 --- a/package/MDAnalysis/transformations/rotate.py +++ b/package/MDAnalysis/transformations/rotate.py @@ -41,7 +41,7 @@ class rotateby(TransformationBase): - ''' + """ Rotates the trajectory by a given angle on a given axis. The axis is defined by the user, combining the direction vector and a point. This point can be the center of geometry or the center of mass of a user defined AtomGroup, or an array defining @@ -86,7 +86,7 @@ class rotateby(TransformationBase): rotation angle in degrees direction: array-like vector that will define the direction of a custom axis of rotation from the - provided point. Expected shapes are (3, ) or (1, 3). + provided point. Expected shapes are (3, ) or (1, 3). ag: AtomGroup, optional use the weighted center of an AtomGroup as the point from where the rotation axis will be defined. If no AtomGroup is given, the `point` argument becomes mandatory @@ -98,12 +98,12 @@ class rotateby(TransformationBase): 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 + 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 - to the atom coordinates are done before calculating the center of the AtomGroup. + to the atom coordinates are done before calculating the center of the AtomGroup. Returns ------- @@ -111,7 +111,7 @@ class rotateby(TransformationBase): Warning ------- - Wrapping/unwrapping the trajectory or performing PBC corrections may not be possible + Wrapping/unwrapping the trajectory or performing PBC corrections may not be possible after rotating the trajectory. @@ -121,18 +121,22 @@ class rotateby(TransformationBase): .. versionchanged:: 2.0.0 The transformation was changed to inherit from the base class for limiting threads and checking if it can be used in parallel analysis. - ''' - def __init__(self, - angle, - direction, - point=None, - ag=None, - weights=None, - wrap=False, - max_threads=1, - parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + """ + + def __init__( + self, + angle, + direction, + point=None, + ag=None, + weights=None, + wrap=False, + max_threads=1, + parallelizable=True, + ): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.angle = angle self.direction = direction @@ -144,38 +148,47 @@ def __init__(self, self.angle = np.deg2rad(self.angle) try: self.direction = np.asarray(self.direction, np.float32) - if self.direction.shape != (3, ) and \ - self.direction.shape != (1, 3): - raise ValueError('{} is not a valid direction' - .format(self.direction)) - self.direction = self.direction.reshape(3, ) + if self.direction.shape != (3,) and self.direction.shape != (1, 3): + raise ValueError( + "{} is not a valid direction".format(self.direction) + ) + self.direction = self.direction.reshape( + 3, + ) except ValueError: - raise ValueError(f'{self.direction} is not a valid direction') \ - from None + raise ValueError( + f"{self.direction} is not a valid direction" + ) from None if self.point is not None: self.point = np.asarray(self.point, np.float32) - if self.point.shape != (3, ) and self.point.shape != (1, 3): - raise ValueError('{} is not a valid point'.format(self.point)) - self.point = self.point.reshape(3, ) + if self.point.shape != (3,) and self.point.shape != (1, 3): + raise ValueError("{} is not a valid point".format(self.point)) + self.point = self.point.reshape( + 3, + ) elif self.ag: try: self.atoms = self.ag.atoms except AttributeError: - raise ValueError(f'{self.ag} is not an AtomGroup object') \ - from None + raise ValueError( + f"{self.ag} is not an AtomGroup object" + ) from None else: try: - self.weights = get_weights(self.atoms, - weights=self.weights) + self.weights = get_weights( + self.atoms, weights=self.weights + ) except (ValueError, TypeError): - errmsg = ("weights must be {'mass', None} or an iterable " - "of the same size as the atomgroup.") + errmsg = ( + "weights must be {'mass', None} or an iterable " + "of the same size as the atomgroup." + ) raise TypeError(errmsg) from None - self.center_method = partial(self.atoms.center, - self.weights, - wrap=self.wrap) + self.center_method = partial( + self.atoms.center, self.weights, wrap=self.wrap + ) else: - raise ValueError('A point or an AtomGroup must be specified') + raise ValueError("A point or an AtomGroup must be specified") def _transform(self, ts): if self.point is None: diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 6edf5d4692..c28fffd404 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -70,10 +70,11 @@ class translate(TransformationBase): The transformation was changed to inherit from the base class for limiting threads and checking if it can be used in parallel analysis. """ - def __init__(self, vector, - max_threads=None, parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + + def __init__(self, vector, max_threads=None, parallelizable=True): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.vector = vector @@ -130,10 +131,19 @@ class center_in_box(TransformationBase): The transformation was changed to inherit from the base class for limiting threads and checking if it can be used in parallel analysis. """ - def __init__(self, ag, center='geometry', point=None, wrap=False, - max_threads=None, parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + + def __init__( + self, + ag, + center="geometry", + point=None, + wrap=False, + max_threads=None, + parallelizable=True, + ): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag self.center = center @@ -143,24 +153,27 @@ def __init__(self, ag, center='geometry', point=None, wrap=False, pbc_arg = self.wrap if self.point: self.point = np.asarray(self.point, np.float32) - if self.point.shape != (3, ) and self.point.shape != (1, 3): - raise ValueError('{} is not a valid point'.format(self.point)) + if self.point.shape != (3,) and self.point.shape != (1, 3): + raise ValueError("{} is not a valid point".format(self.point)) try: - if self.center == 'geometry': - self.center_method = partial(self.ag.center_of_geometry, - wrap=pbc_arg) - elif self.center == 'mass': - self.center_method = partial(self.ag.center_of_mass, - wrap=pbc_arg) + if self.center == "geometry": + self.center_method = partial( + self.ag.center_of_geometry, wrap=pbc_arg + ) + elif self.center == "mass": + self.center_method = partial( + self.ag.center_of_mass, wrap=pbc_arg + ) else: - raise ValueError(f'{self.center} is valid for center') + raise ValueError(f"{self.center} is valid for center") except AttributeError: - if self.center == 'mass': - errmsg = f'{self.ag} is not an AtomGroup object with masses' + if self.center == "mass": + errmsg = f"{self.ag} is not an AtomGroup object with masses" raise AttributeError(errmsg) from None else: - raise ValueError(f'{self.ag} is not an AtomGroup object') \ - from None + raise ValueError( + f"{self.ag} is not an AtomGroup object" + ) from None def _transform(self, ts): if self.point is None: diff --git a/package/MDAnalysis/transformations/wrap.py b/package/MDAnalysis/transformations/wrap.py index f077f5edc1..f8c1d8dbae 100644 --- a/package/MDAnalysis/transformations/wrap.py +++ b/package/MDAnalysis/transformations/wrap.py @@ -42,7 +42,7 @@ class wrap(TransformationBase): """ Shift the contents of a given AtomGroup back into the unit cell. :: - + +-----------+ +-----------+ | | | | | 3 | 6 | 6 3 | @@ -52,24 +52,24 @@ class wrap(TransformationBase): | 4 | 7 | 7 4 | | | | | +-----------+ +-----------+ - + Example ------- - + .. code-block:: python - - ag = u.atoms + + ag = u.atoms transform = mda.transformations.wrap(ag) u.trajectory.add_transformations(transform) - + Parameters ---------- - + ag: Atomgroup Atomgroup to be wrapped in the unit cell compound : {'atoms', 'group', 'residues', 'segments', 'fragments'}, optional The group which will be kept together through the shifting process. - + Notes ----- When specifying a `compound`, the translation is calculated based on @@ -77,7 +77,7 @@ class wrap(TransformationBase): within this compound, meaning it will not be broken by the shift. This might however mean that not all atoms from the compound are inside the unit cell, but rather the center of the compound is. - + Returns ------- MDAnalysis.coordinates.timestep.Timestep @@ -90,10 +90,13 @@ class wrap(TransformationBase): The transformation was changed to inherit from the base class for limiting threads and checking if it can be used in parallel analysis. """ - def __init__(self, ag, compound='atoms', - max_threads=None, parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + + def __init__( + self, ag, compound="atoms", max_threads=None, parallelizable=True + ): + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag self.compound = compound @@ -113,7 +116,7 @@ class unwrap(TransformationBase): unit cell, causing breaks mid molecule, with the molecule then appearing on either side of the unit cell. This is problematic for operations such as calculating the center of mass of the molecule. :: - + +-----------+ +-----------+ | | | | | 6 3 | | 3 | 6 @@ -123,22 +126,22 @@ class unwrap(TransformationBase): | 7 4 | | 4 | 7 | | | | +-----------+ +-----------+ - + Example ------- - + .. code-block:: python - - ag = u.atoms + + ag = u.atoms transform = mda.transformations.unwrap(ag) u.trajectory.add_transformations(transform) - + Parameters ---------- atomgroup : AtomGroup The :class:`MDAnalysis.core.groups.AtomGroup` to work with. The positions of this are modified in place. - + Returns ------- MDAnalysis.coordinates.timestep.Timestep @@ -151,9 +154,11 @@ class unwrap(TransformationBase): The transformation was changed to inherit from the base class for limiting threads and checking if it can be used in parallel analysis. """ + def __init__(self, ag, max_threads=None, parallelizable=True): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag diff --git a/package/pyproject.toml b/package/pyproject.toml index 97217c60e5..72a372ccef 100644 --- a/package/pyproject.toml +++ b/package/pyproject.toml @@ -133,6 +133,7 @@ tables\.py | setup\.py | MDAnalysis/auxiliary/.*\.py | visualization/.*\.py +| MDAnalysis/transformations/.*\.py ) ''' extend-exclude = '__pycache__' diff --git a/testsuite/MDAnalysisTests/transformations/test_base.py b/testsuite/MDAnalysisTests/transformations/test_base.py index 5aa170f560..492c2825b4 100644 --- a/testsuite/MDAnalysisTests/transformations/test_base.py +++ b/testsuite/MDAnalysisTests/transformations/test_base.py @@ -1,4 +1,3 @@ - # -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 fileencoding=utf-8 # @@ -32,6 +31,7 @@ class DefaultTransformation(TransformationBase): """Default values for max_threads and parallelizable""" + def __init__(self): super().__init__() @@ -43,15 +43,18 @@ def _transform(self, ts): class NoTransform_Transformation(TransformationBase): """Default values for max_threads and parallelizable""" + def __init__(self): super().__init__() class CustomTransformation(TransformationBase): """Custom value for max_threads and parallelizable""" + def __init__(self, max_threads=1, parallelizable=False): - super().__init__(max_threads=max_threads, - parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) def _transform(self, ts): self.runtime_info = threadpool_info() @@ -59,7 +62,7 @@ def _transform(self, ts): return ts -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def u(): return mda.Universe(PSF, DCD) @@ -89,16 +92,18 @@ def test_setting_thread_limit_value(): def test_thread_limit_apply(u): default_thread_info = threadpool_info() - default_num_thread_limit_list = [thread_info['num_threads'] - for thread_info in default_thread_info] + default_num_thread_limit_list = [ + thread_info["num_threads"] for thread_info in default_thread_info + ] new_trans = CustomTransformation(max_threads=2) _ = new_trans(u.trajectory.ts) for thread_info in new_trans.runtime_info: - assert thread_info['num_threads'] == 2 + assert thread_info["num_threads"] == 2 # test the thread limit is only applied locally. new_thread_info = threadpool_info() - new_num_thread_limit_list = [thread_info['num_threads'] - for thread_info in new_thread_info] + new_num_thread_limit_list = [ + thread_info["num_threads"] for thread_info in new_thread_info + ] assert_equal(default_num_thread_limit_list, new_num_thread_limit_list) diff --git a/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py b/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py index f8bb30a7f2..a1d88b7840 100644 --- a/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py +++ b/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py @@ -51,46 +51,56 @@ def variable_boxdimensions_universe(): def test_boxdimensions_dims(boxdimensions_universe): new_dims = np.float32([2, 2, 2, 90, 90, 90]) set_dimensions(new_dims)(boxdimensions_universe.trajectory.ts) - assert_array_almost_equal(boxdimensions_universe.dimensions, - new_dims, decimal=6) - - -@pytest.mark.parametrize('dim_vector_shapes', ( - [1, 1, 1, 90, 90], - [1, 1, 1, 1, 90, 90, 90], - np.array([[1], [1], [90], [90], [90]]), - np.array([1, 1, 1, 90, 90]), - np.array([1, 1, 1, 1, 90, 90, 90]), - [1, 1, 1, 90, 90], - 111909090) + assert_array_almost_equal( + boxdimensions_universe.dimensions, new_dims, decimal=6 ) + + +@pytest.mark.parametrize( + "dim_vector_shapes", + ( + [1, 1, 1, 90, 90], + [1, 1, 1, 1, 90, 90, 90], + np.array([[1], [1], [90], [90], [90]]), + np.array([1, 1, 1, 90, 90]), + np.array([1, 1, 1, 1, 90, 90, 90]), + [1, 1, 1, 90, 90], + 111909090, + ), +) def test_dimensions_vector(boxdimensions_universe, dim_vector_shapes): # wrong box dimension vector shape ts = boxdimensions_universe.trajectory.ts - with pytest.raises(ValueError, match='valid box dimension shape'): + with pytest.raises(ValueError, match="valid box dimension shape"): set_dimensions(dim_vector_shapes)(ts) -@pytest.mark.parametrize('dim_vector_forms_dtypes', ( - ['a', 'b', 'c', 'd', 'e', 'f'], - np.array(['a', 'b', 'c', 'd', 'e', 'f']), - 'abcd') - ) -def test_dimensions_vector_asarray(boxdimensions_universe, - dim_vector_forms_dtypes): +@pytest.mark.parametrize( + "dim_vector_forms_dtypes", + ( + ["a", "b", "c", "d", "e", "f"], + np.array(["a", "b", "c", "d", "e", "f"]), + "abcd", + ), +) +def test_dimensions_vector_asarray( + boxdimensions_universe, dim_vector_forms_dtypes +): # box dimension input type not convertible into array ts = boxdimensions_universe.trajectory.ts - with pytest.raises(ValueError, match='cannot be converted'): + with pytest.raises(ValueError, match="cannot be converted"): set_dimensions(dim_vector_forms_dtypes)(ts) + def test_dimensions_transformations_api(boxdimensions_universe): # test if transformation works with on-the-fly transformations API new_dims = np.float32([2, 2, 2, 90, 90, 90]) transform = set_dimensions(new_dims) boxdimensions_universe.trajectory.add_transformations(transform) for ts in boxdimensions_universe.trajectory: - assert_array_almost_equal(boxdimensions_universe.dimensions, - new_dims, decimal=6) + assert_array_almost_equal( + boxdimensions_universe.dimensions, new_dims, decimal=6 + ) def test_varying_dimensions_transformations_api( @@ -100,16 +110,21 @@ def test_varying_dimensions_transformations_api( Test if transformation works with on-the-fly transformations API when we have varying dimensions. """ - new_dims = np.float32([ - [2, 2, 2, 90, 90, 90], - [4, 4, 4, 90, 90, 90], - [8, 8, 8, 90, 90, 90], - ]) + new_dims = np.float32( + [ + [2, 2, 2, 90, 90, 90], + [4, 4, 4, 90, 90, 90], + [8, 8, 8, 90, 90, 90], + ] + ) transform = set_dimensions(new_dims) variable_boxdimensions_universe.trajectory.add_transformations(transform) for ts in variable_boxdimensions_universe.trajectory: - assert_array_almost_equal(variable_boxdimensions_universe.dimensions, - new_dims[ts.frame], decimal=6) + assert_array_almost_equal( + variable_boxdimensions_universe.dimensions, + new_dims[ts.frame], + decimal=6, + ) def test_varying_dimensions_no_data( @@ -120,10 +135,16 @@ def test_varying_dimensions_no_data( in a trajectory. """ # trjactory has three frames - new_dims = np.float32([ - [2, 2, 2, 90, 90, 90], - [4, 4, 4, 90, 90, 90], - ]) + new_dims = np.float32( + [ + [2, 2, 2, 90, 90, 90], + [4, 4, 4, 90, 90, 90], + ] + ) transform = set_dimensions(new_dims) - with pytest.raises(ValueError, match="Dimensions array has no data for frame 2"): - variable_boxdimensions_universe.trajectory.add_transformations(transform) + with pytest.raises( + ValueError, match="Dimensions array has no data for frame 2" + ): + variable_boxdimensions_universe.trajectory.add_transformations( + transform + ) diff --git a/testsuite/MDAnalysisTests/transformations/test_fit.py b/testsuite/MDAnalysisTests/transformations/test_fit.py index 9c44f88e0d..ecd4a87dd7 100644 --- a/testsuite/MDAnalysisTests/transformations/test_fit.py +++ b/testsuite/MDAnalysisTests/transformations/test_fit.py @@ -31,61 +31,62 @@ @pytest.fixture() def fit_universe(): # make a test universe - test = make_Universe(('masses', ), trajectory=True) - ref = make_Universe(('masses', ), trajectory=True) + test = make_Universe(("masses",), trajectory=True) + ref = make_Universe(("masses",), trajectory=True) ref.atoms.positions += np.asarray([10, 10, 10], np.float32) return test, ref -@pytest.mark.parametrize('universe', ( - [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) +@pytest.mark.parametrize( + "universe", + ( + [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_fit_translation_bad_ag(fit_universe, universe): ts = fit_universe[0].trajectory.ts test_u = fit_universe[0] - ref_u = fit_universe[1] + ref_u = fit_universe[1] # what happens if something other than an AtomGroup or Universe is given? with pytest.raises(AttributeError): fit_translation(universe, ref_u)(ts) -@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]])) +@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_fit_translation_bad_weights(fit_universe, weights): ts = fit_universe[0].trajectory.ts test_u = fit_universe[0] - ref_u = fit_universe[1] + ref_u = fit_universe[1] # what happens if a bad string for center is given? with pytest.raises(ValueError): fit_translation(test_u, ref_u, weights=weights)(ts) -@pytest.mark.parametrize('plane', ( - 1, - [0, 1], - [0, 1, 2, 3, 4], - np.array([0, 1]), - "xyz", - "notaplane") +@pytest.mark.parametrize( + "plane", (1, [0, 1], [0, 1, 2, 3, 4], np.array([0, 1]), "xyz", "notaplane") ) def test_fit_translation_bad_plane(fit_universe, plane): ts = fit_universe[0].trajectory.ts test_u = fit_universe[0] - ref_u = fit_universe[1] + ref_u = fit_universe[1] # what happens if a bad string for center is given? with pytest.raises(ValueError): fit_translation(test_u, ref_u, plane=plane)(ts) @@ -95,11 +96,11 @@ def test_fit_translation_no_masses(fit_universe): ts = fit_universe[0].trajectory.ts test_u = fit_universe[0] # create a universe without masses - ref_u = make_Universe() + ref_u = make_Universe() # what happens Universe without masses is given? with pytest.raises(TypeError) as exc: fit_translation(test_u, ref_u, weights="mass")(ts) - assert 'atoms.masses is missing' in str(exc.value) + assert "atoms.masses is missing" in str(exc.value) def test_fit_translation_no_options(fit_universe): @@ -107,31 +108,37 @@ def test_fit_translation_no_options(fit_universe): ref_u = fit_universe[1] fit_translation(test_u, ref_u)(test_u.trajectory.ts) # what happens when no options are passed? - assert_array_almost_equal(test_u.trajectory.ts.positions, ref_u.trajectory.ts.positions, decimal=6) + assert_array_almost_equal( + test_u.trajectory.ts.positions, + ref_u.trajectory.ts.positions, + decimal=6, + ) + def test_fit_translation_residue_mismatch(fit_universe): test_u = fit_universe[0] ref_u = fit_universe[1].residues[:-1].atoms - with pytest.raises(ValueError, match='number of residues'): + with pytest.raises(ValueError, match="number of residues"): fit_translation(test_u, ref_u)(test_u.trajectory.ts) + def test_fit_translation_com(fit_universe): test_u = fit_universe[0] ref_u = fit_universe[1] fit_translation(test_u, ref_u, weights="mass")(test_u.trajectory.ts) # what happens when the center o mass is used? - assert_array_almost_equal(test_u.trajectory.ts.positions, ref_u.trajectory.ts.positions, decimal=6) + assert_array_almost_equal( + test_u.trajectory.ts.positions, + ref_u.trajectory.ts.positions, + decimal=6, + ) -@pytest.mark.parametrize('plane', ( - "yz", - "xz", - "xy") -) +@pytest.mark.parametrize("plane", ("yz", "xz", "xy")) def test_fit_translation_plane(fit_universe, plane): test_u = fit_universe[0] ref_u = fit_universe[1] - axes = {'yz' : 0, 'xz' : 1, 'xy' : 2} + axes = {"yz": 0, "xz": 1, "xy": 2} idx = axes[plane] # translate the test universe on the plane coordinates only fit_translation(test_u, ref_u, plane=plane)(test_u.trajectory.ts) @@ -139,18 +146,24 @@ def test_fit_translation_plane(fit_universe, plane): shiftz = np.asanyarray([0, 0, 0], np.float32) shiftz[idx] = -10 ref_coordinates = ref_u.trajectory.ts.positions + shiftz - assert_array_almost_equal(test_u.trajectory.ts.positions, ref_coordinates, decimal=6) + assert_array_almost_equal( + test_u.trajectory.ts.positions, ref_coordinates, decimal=6 + ) def test_fit_translation_all_options(fit_universe): test_u = fit_universe[0] ref_u = fit_universe[1] # translate the test universe on the x and y coordinates only - fit_translation(test_u, ref_u, plane="xy", weights="mass")(test_u.trajectory.ts) + fit_translation(test_u, ref_u, plane="xy", weights="mass")( + test_u.trajectory.ts + ) # the reference is 10 angstrom in the z coordinate above the test universe shiftz = np.asanyarray([0, 0, -10], np.float32) ref_coordinates = ref_u.trajectory.ts.positions + shiftz - assert_array_almost_equal(test_u.trajectory.ts.positions, ref_coordinates, decimal=6) + assert_array_almost_equal( + test_u.trajectory.ts.positions, ref_coordinates, decimal=6 + ) def test_fit_translation_transformations_api(fit_universe): @@ -158,42 +171,52 @@ def test_fit_translation_transformations_api(fit_universe): ref_u = fit_universe[1] transform = fit_translation(test_u, ref_u) test_u.trajectory.add_transformations(transform) - assert_array_almost_equal(test_u.trajectory.ts.positions, ref_u.trajectory.ts.positions, decimal=6) - - -@pytest.mark.parametrize('universe', ( - [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) + assert_array_almost_equal( + test_u.trajectory.ts.positions, + ref_u.trajectory.ts.positions, + decimal=6, + ) + + +@pytest.mark.parametrize( + "universe", + ( + [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_fit_rot_trans_bad_universe(fit_universe, universe): test_u = fit_universe[0] - ref_u= universe + ref_u = universe with pytest.raises(AttributeError): fit_rot_trans(test_u, ref_u)(test_u.trajectory.ts) def test_fit_rot_trans_shorter_universe(fit_universe): ref_u = fit_universe[1] - bad_u =fit_universe[0].atoms[0:5] - test_u= bad_u + bad_u = fit_universe[0].atoms[0:5] + test_u = bad_u with pytest.raises(ValueError): fit_rot_trans(test_u, ref_u)(test_u.trajectory.ts) -@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]])) +@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_fit_rot_trans_bad_weights(fit_universe, weights): test_u = fit_universe[0] @@ -203,15 +226,18 @@ def test_fit_rot_trans_bad_weights(fit_universe, weights): fit_rot_trans(test_u, ref_u, weights=bad_weights)(test_u.trajectory.ts) -@pytest.mark.parametrize('plane', ( - " ", - "totallynotaplane", - "xyz", - 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]])) +@pytest.mark.parametrize( + "plane", + ( + " ", + "totallynotaplane", + "xyz", + 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_fit_rot_trans_bad_plane(fit_universe, plane): test_u = fit_universe[0] @@ -225,18 +251,18 @@ def test_fit_rot_trans_no_options(fit_universe): ref_u = fit_universe[1] ref_com = ref_u.atoms.center(None) ref_u.trajectory.ts.positions -= ref_com - R = rotation_matrix(np.pi/3, [1,0,0])[:3,:3] + R = rotation_matrix(np.pi / 3, [1, 0, 0])[:3, :3] ref_u.trajectory.ts.positions = np.dot(ref_u.trajectory.ts.positions, R) ref_u.trajectory.ts.positions += ref_com fit_rot_trans(test_u, ref_u)(test_u.trajectory.ts) - assert_array_almost_equal(test_u.trajectory.ts.positions, ref_u.trajectory.ts.positions, decimal=3) + assert_array_almost_equal( + test_u.trajectory.ts.positions, + ref_u.trajectory.ts.positions, + decimal=3, + ) -@pytest.mark.parametrize('plane', ( - "yz", - "xz", - "xy") -) +@pytest.mark.parametrize("plane", ("yz", "xz", "xy")) def test_fit_rot_trans_plane(fit_universe, plane): # the reference is rotated in the x axis so removing the translations and rotations # in the yz plane should return the same as the fitting without specifying a plane @@ -244,17 +270,21 @@ def test_fit_rot_trans_plane(fit_universe, plane): ref_u = fit_universe[1] ref_com = ref_u.atoms.center(None) mobile_com = test_u.atoms.center(None) - axes = {'yz' : 0, 'xz' : 1, 'xy' : 2} + axes = {"yz": 0, "xz": 1, "xy": 2} idx = axes[plane] - rotaxis = np.asarray([0,0,0]) - rotaxis[idx]=1 + rotaxis = np.asarray([0, 0, 0]) + rotaxis[idx] = 1 ref_u.trajectory.ts.positions -= ref_com - R = rotation_matrix(np.pi/3, rotaxis)[:3,:3] + R = rotation_matrix(np.pi / 3, rotaxis)[:3, :3] ref_u.trajectory.ts.positions = np.dot(ref_u.trajectory.ts.positions, R) ref_com[idx] = mobile_com[idx] ref_u.trajectory.ts.positions += ref_com fit_rot_trans(test_u, ref_u, plane=plane)(test_u.trajectory.ts) - assert_array_almost_equal(test_u.trajectory.ts.positions[:,idx], ref_u.trajectory.ts.positions[:,idx], decimal=3) + assert_array_almost_equal( + test_u.trajectory.ts.positions[:, idx], + ref_u.trajectory.ts.positions[:, idx], + decimal=3, + ) def test_fit_rot_trans_transformations_api(fit_universe): @@ -262,9 +292,13 @@ def test_fit_rot_trans_transformations_api(fit_universe): ref_u = fit_universe[1] ref_com = ref_u.atoms.center(None) ref_u.trajectory.ts.positions -= ref_com - R = rotation_matrix(np.pi/3, [1,0,0])[:3,:3] + R = rotation_matrix(np.pi / 3, [1, 0, 0])[:3, :3] ref_u.trajectory.ts.positions = np.dot(ref_u.trajectory.ts.positions, R) ref_u.trajectory.ts.positions += ref_com transform = fit_rot_trans(test_u, ref_u) test_u.trajectory.add_transformations(transform) - assert_array_almost_equal(test_u.trajectory.ts.positions, ref_u.trajectory.ts.positions, decimal=3) + assert_array_almost_equal( + test_u.trajectory.ts.positions, + ref_u.trajectory.ts.positions, + decimal=3, + ) diff --git a/testsuite/MDAnalysisTests/transformations/test_nojump.py b/testsuite/MDAnalysisTests/transformations/test_nojump.py index 6bbabe370f..f295ec33a7 100644 --- a/testsuite/MDAnalysisTests/transformations/test_nojump.py +++ b/testsuite/MDAnalysisTests/transformations/test_nojump.py @@ -9,9 +9,9 @@ @pytest.fixture() def nojump_universes_fromfile(): - ''' + """ Create the universe objects for the tests. - ''' + """ u = mda.Universe(data.PSF_TRICLINIC, data.DCD_TRICLINIC) transformation = NoJump() u.trajectory.add_transformations(transformation) @@ -113,18 +113,24 @@ def nojump_universe_npt_2nd_frame_from_file(tmp_path_factory): coordinates[2] = [2.5, 50.0, 50.0] coordinates[3] = [2.5, 50.0, 50.0] u.load_new(coordinates, order="fac") - dim = np.asarray([ - [100, 100, 100, 90, 90, 90], - [95, 100, 100, 90, 90, 90], # Box shrinks by 5 in the x-dimension - [95, 100, 100, 90, 90, 90], - [95, 100, 100, 90, 90, 90], - ]) + dim = np.asarray( + [ + [100, 100, 100, 90, 90, 90], + [95, 100, 100, 90, 90, 90], # Box shrinks by 5 in the x-dimension + [95, 100, 100, 90, 90, 90], + [95, 100, 100, 90, 90, 90], + ] + ) workflow = [ mda.transformations.boxdimensions.set_dimensions(dim), ] u.trajectory.add_transformations(*workflow) - tmp_pdb = (tmp_path_factory.getbasetemp() / "nojump_npt_2nd_frame.pdb").as_posix() - tmp_xtc = (tmp_path_factory.getbasetemp() / "nojump_npt_2nd_frame.xtc").as_posix() + tmp_pdb = ( + tmp_path_factory.getbasetemp() / "nojump_npt_2nd_frame.pdb" + ).as_posix() + tmp_xtc = ( + tmp_path_factory.getbasetemp() / "nojump_npt_2nd_frame.xtc" + ).as_posix() u.atoms.write(tmp_pdb) with mda.Writer(tmp_xtc) as f: for ts in u.trajectory: @@ -139,7 +145,10 @@ def test_nojump_orthogonal_fwd(nojump_universe): """ u = nojump_universe dim = np.asarray([1, 1, 1, 90, 90, 90], np.float32) - workflow = [mda.transformations.boxdimensions.set_dimensions(dim), NoJump()] + workflow = [ + mda.transformations.boxdimensions.set_dimensions(dim), + NoJump(), + ] u.trajectory.add_transformations(*workflow) transformed_coordinates = u.trajectory.timeseries()[0] # Step is 1 unit every 3 steps. After 99 steps from the origin, @@ -160,7 +169,10 @@ def test_nojump_nonorthogonal_fwd(nojump_universe): # [0. 1. 0. ] # [0.5 0. 0.8660254]] dim = np.asarray([1, 1, 1, 90, 60, 90], np.float32) - workflow = [mda.transformations.boxdimensions.set_dimensions(dim), NoJump()] + workflow = [ + mda.transformations.boxdimensions.set_dimensions(dim), + NoJump(), + ] u.trajectory.add_transformations(*workflow) transformed_coordinates = u.trajectory.timeseries()[0] # After the transformation, you should end up in a repeating pattern, since you are @@ -173,13 +185,15 @@ def test_nojump_nonorthogonal_fwd(nojump_universe): ) assert_allclose( transformed_coordinates[1::3], - np.outer(np.arange(32.5), np.array([0.5, 1, np.sqrt(3) / 2])) + 1 * np.ones(3) / 3, - rtol=1.2e-7 + np.outer(np.arange(32.5), np.array([0.5, 1, np.sqrt(3) / 2])) + + 1 * np.ones(3) / 3, + rtol=1.2e-7, ) assert_allclose( transformed_coordinates[2::3], - np.outer(np.arange(32.5), np.array([0.5, 1, np.sqrt(3) / 2])) + 2 * np.ones(3) / 3, - rtol=1.2e-7 + np.outer(np.arange(32.5), np.array([0.5, 1, np.sqrt(3) / 2])) + + 2 * np.ones(3) / 3, + rtol=1.2e-7, ) @@ -189,7 +203,9 @@ def test_nojump_constantvel(nojump_constantvel_universe): values when iterating forwards over the sample trajectory. """ ref = nojump_constantvel_universe - towrap = ref.copy() # This copy of the universe will be wrapped, then unwrapped, + towrap = ( + ref.copy() + ) # This copy of the universe will be wrapped, then unwrapped, # and should be equal to ref. dim = np.asarray([5, 5, 5, 54, 60, 90], np.float32) workflow = [ @@ -225,12 +241,14 @@ def test_nojump_2nd_frame(nojump_universe_npt_2nd_frame): unwrapped = [97.5, 50.0, 50.0] """ u = nojump_universe_npt_2nd_frame - dim = np.asarray([ - [100, 100, 100, 90, 90, 90], - [95, 100, 100, 90, 90, 90], # Box shrinks by 5 in the x-dimension - [95, 100, 100, 90, 90, 90], - [95, 100, 100, 90, 90, 90], - ]) + dim = np.asarray( + [ + [100, 100, 100, 90, 90, 90], + [95, 100, 100, 90, 90, 90], # Box shrinks by 5 in the x-dimension + [95, 100, 100, 90, 90, 90], + [95, 100, 100, 90, 90, 90], + ] + ) workflow = [ mda.transformations.boxdimensions.set_dimensions(dim), NoJump(), @@ -259,12 +277,14 @@ def test_nojump_3rd_frame(nojump_universe_npt_3rd_frame): unwrapped = [97.5, 50.0, 50.0] """ u = nojump_universe_npt_3rd_frame - dim = np.asarray([ - [100, 100, 100, 90, 90, 90], - [100, 100, 100, 90, 90, 90], - [95, 100, 100, 90, 90, 90], # Box shrinks by 5 in the x-dimension - [95, 100, 100, 90, 90, 90], - ]) + dim = np.asarray( + [ + [100, 100, 100, 90, 90, 90], + [100, 100, 100, 90, 90, 90], + [95, 100, 100, 90, 90, 90], # Box shrinks by 5 in the x-dimension + [95, 100, 100, 90, 90, 90], + ] + ) workflow = [ mda.transformations.boxdimensions.set_dimensions(dim), NoJump(), @@ -283,7 +303,9 @@ def test_nojump_iterate_twice(nojump_universe_npt_2nd_frame_from_file): u.trajectory.add_transformations(NoJump()) timeseries_first_iteration = u.trajectory.timeseries() timeseries_second_iteration = u.trajectory.timeseries() - np.testing.assert_allclose(timeseries_first_iteration, timeseries_second_iteration) + np.testing.assert_allclose( + timeseries_first_iteration, timeseries_second_iteration + ) def test_nojump_constantvel_skip(nojump_universes_fromfile): @@ -293,7 +315,7 @@ def test_nojump_constantvel_skip(nojump_universes_fromfile): with pytest.warns(UserWarning): u = nojump_universes_fromfile u.trajectory[0] - u.trajectory[9] #Exercises the warning. + u.trajectory[9] # Exercises the warning. def test_nojump_constantvel_stride_2(nojump_universes_fromfile): @@ -351,6 +373,9 @@ def test_notinvertible(nojump_universe): with pytest.raises(mda.exceptions.NoDataError): u = nojump_universe dim = [1, 0, 0, 90, 90, 90] - workflow = [mda.transformations.boxdimensions.set_dimensions(dim),NoJump()] + workflow = [ + mda.transformations.boxdimensions.set_dimensions(dim), + NoJump(), + ] u.trajectory.add_transformations(*workflow) transformed_coordinates = u.trajectory.timeseries()[0] diff --git a/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py b/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py index ba2c348bd0..71e4251366 100644 --- a/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py +++ b/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py @@ -8,104 +8,122 @@ from MDAnalysis.transformations import PositionAverager from MDAnalysisTests import datafiles + @pytest.fixture() def posaveraging_universes(): - ''' + """ Create the universe objects for the tests. - ''' + """ u = md.Universe(datafiles.XTC_multi_frame, to_guess=()) transformation = PositionAverager(3) u.trajectory.add_transformations(transformation) return u + @pytest.fixture() def posaveraging_universes_noreset(): - ''' + """ Create the universe objects for the tests. Position averaging reset is set to False. - ''' - u = md.Universe(datafiles.XTC_multi_frame, to_guess=()) + """ + u = md.Universe(datafiles.XTC_multi_frame, to_guess=()) transformation = PositionAverager(3, check_reset=False) u.trajectory.add_transformations(transformation) - return u + return u + def test_posavging_fwd(posaveraging_universes): - ''' + """ Test if the position averaging function is returning the correct values when iterating forwards over the trajectory. - ''' - ref_matrix_fwd = np.asarray([80., 80., 80.]) - size = (posaveraging_universes.trajectory.ts.positions.shape[0], - posaveraging_universes.trajectory.ts.positions.shape[1], - len(posaveraging_universes.trajectory)) - avgd = np.empty(size) + """ + ref_matrix_fwd = np.asarray([80.0, 80.0, 80.0]) + size = ( + posaveraging_universes.trajectory.ts.positions.shape[0], + posaveraging_universes.trajectory.ts.positions.shape[1], + len(posaveraging_universes.trajectory), + ) + avgd = np.empty(size) for ts in posaveraging_universes.trajectory: - avgd[...,ts.frame] = ts.positions.copy() - - assert_array_almost_equal(ref_matrix_fwd, avgd[1,:,-1], decimal=5) + avgd[..., ts.frame] = ts.positions.copy() + + assert_array_almost_equal(ref_matrix_fwd, avgd[1, :, -1], decimal=5) + def test_posavging_bwd(posaveraging_universes): - ''' + """ Test if the position averaging function is returning the correct values when iterating backwards over the trajectory. - ''' - ref_matrix_bwd = np.asarray([10., 10., 10.]) - size = (posaveraging_universes.trajectory.ts.positions.shape[0], - posaveraging_universes.trajectory.ts.positions.shape[1], - len(posaveraging_universes.trajectory)) + """ + ref_matrix_bwd = np.asarray([10.0, 10.0, 10.0]) + size = ( + posaveraging_universes.trajectory.ts.positions.shape[0], + posaveraging_universes.trajectory.ts.positions.shape[1], + len(posaveraging_universes.trajectory), + ) back_avgd = np.empty(size) for ts in posaveraging_universes.trajectory[::-1]: - back_avgd[...,9-ts.frame] = ts.positions.copy() - assert_array_almost_equal(ref_matrix_bwd, back_avgd[1,:,-1], decimal=5) + back_avgd[..., 9 - ts.frame] = ts.positions.copy() + assert_array_almost_equal(ref_matrix_bwd, back_avgd[1, :, -1], decimal=5) + def test_posavging_reset(posaveraging_universes): - ''' + """ Test if the automatic reset is working as intended. - ''' - size = (posaveraging_universes.trajectory.ts.positions.shape[0], - posaveraging_universes.trajectory.ts.positions.shape[1], - len(posaveraging_universes.trajectory)) - avgd = np.empty(size) + """ + size = ( + posaveraging_universes.trajectory.ts.positions.shape[0], + posaveraging_universes.trajectory.ts.positions.shape[1], + len(posaveraging_universes.trajectory), + ) + avgd = np.empty(size) for ts in posaveraging_universes.trajectory: - avgd[...,ts.frame] = ts.positions.copy() + avgd[..., ts.frame] = ts.positions.copy() after_reset = ts.positions.copy() - assert_array_almost_equal(avgd[...,0], after_reset, decimal=5) + assert_array_almost_equal(avgd[..., 0], after_reset, decimal=5) + def test_posavging_specific(posaveraging_universes): - ''' + """ Test if the position averaging function is returning the correct values when iterating over arbitrary non-sequential frames. check_reset=True - ''' - ref_matrix_specr = np.asarray([30., 30., 30.]) + """ + ref_matrix_specr = np.asarray([30.0, 30.0, 30.0]) fr_list = [0, 1, 7, 3] - size = (posaveraging_universes.trajectory.ts.positions.shape[0], - posaveraging_universes.trajectory.ts.positions.shape[1], - len(fr_list)) + size = ( + posaveraging_universes.trajectory.ts.positions.shape[0], + posaveraging_universes.trajectory.ts.positions.shape[1], + len(fr_list), + ) specr_avgd = np.empty(size) idx = 0 for ts in posaveraging_universes.trajectory[fr_list]: - specr_avgd[...,idx] = ts.positions.copy() + specr_avgd[..., idx] = ts.positions.copy() idx += 1 - assert_array_almost_equal(ref_matrix_specr, specr_avgd[1,:,-1], decimal=5) - + assert_array_almost_equal( + ref_matrix_specr, specr_avgd[1, :, -1], decimal=5 + ) + + def test_posavging_specific_noreset(posaveraging_universes_noreset): - ''' + """ Test if the position averaging function is returning the correct values when iterating over arbitrary non-sequential frames. check_reset=False - ''' + """ ref_matrix_specr = np.asarray([36.66667, 36.66667, 36.66667]) fr_list = [0, 1, 7, 3] - size = (posaveraging_universes_noreset.trajectory.ts.positions.shape[0], - posaveraging_universes_noreset.trajectory.ts.positions.shape[1], - len(fr_list)) + size = ( + posaveraging_universes_noreset.trajectory.ts.positions.shape[0], + posaveraging_universes_noreset.trajectory.ts.positions.shape[1], + len(fr_list), + ) specr_avgd = np.empty(size) idx = 0 for ts in posaveraging_universes_noreset.trajectory[fr_list]: - specr_avgd[...,idx] = ts.positions.copy() + specr_avgd[..., idx] = ts.positions.copy() idx += 1 - assert_array_almost_equal(ref_matrix_specr, specr_avgd[1,:,-1], decimal=5) - - - + assert_array_almost_equal( + ref_matrix_specr, specr_avgd[1, :, -1], decimal=5 + ) diff --git a/testsuite/MDAnalysisTests/transformations/test_rotate.py b/testsuite/MDAnalysisTests/transformations/test_rotate.py index 77ffd56164..4f8fd9867b 100644 --- a/testsuite/MDAnalysisTests/transformations/test_rotate.py +++ b/testsuite/MDAnalysisTests/transformations/test_rotate.py @@ -21,21 +21,24 @@ # J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787 # +import MDAnalysis as mda import numpy as np import pytest +from MDAnalysis.lib.transformations import rotation_matrix +from MDAnalysis.transformations import rotateby from numpy.testing import assert_array_almost_equal -import MDAnalysis as mda -from MDAnalysis.transformations import rotateby -from MDAnalysis.lib.transformations import rotation_matrix from MDAnalysisTests import make_Universe + @pytest.fixture() def rotate_universes(): # create the Universe objects for the tests reference = make_Universe(trajectory=True) - transformed = make_Universe(['masses'], trajectory=True) - transformed.trajectory.ts.dimensions = np.array([372., 373., 374., 90, 90, 90]) + transformed = make_Universe(["masses"], trajectory=True) + transformed.trajectory.ts.dimensions = np.array( + [372.0, 373.0, 374.0, 90, 90, 90] + ) return reference, transformed @@ -45,24 +48,34 @@ def test_rotation_matrix(): angle = 180 vector = [0, 0, 1] pos = [0, 0, 0] - ref_matrix = np.asarray([[-1, 0, 0], - [0, -1, 0], - [0, 0, 1]], np.float64) + ref_matrix = np.asarray( + [ + [-1, 0, 0], + [0, -1, 0], + [0, 0, 1], + ], + np.float64, + ) matrix = rotation_matrix(np.deg2rad(angle), vector, pos)[:3, :3] assert_array_almost_equal(matrix, ref_matrix, decimal=6) # another angle in a custom axis angle = 60 vector = [1, 2, 3] pos = [1, 2, 3] - ref_matrix = np.asarray([[ 0.53571429, -0.6229365 , 0.57005291], - [ 0.76579365, 0.64285714, -0.01716931], - [-0.35576719, 0.44574074, 0.82142857]], np.float64) + ref_matrix = np.asarray( + [ + [0.53571429, -0.6229365, 0.57005291], + [0.76579365, 0.64285714, -0.01716931], + [-0.35576719, 0.44574074, 0.82142857], + ], + np.float64, + ) matrix = rotation_matrix(np.deg2rad(angle), vector, pos)[:3, :3] assert_array_almost_equal(matrix, ref_matrix, decimal=6) - -@pytest.mark.parametrize('point', ( - np.asarray([0, 0, 0]), - np.asarray([[0, 0, 0]])) + + +@pytest.mark.parametrize( + "point", (np.asarray([0, 0, 0]), np.asarray([[0, 0, 0]])) ) def test_rotateby_custom_point(rotate_universes, point): # what happens when we use a custom point for the axis of rotation? @@ -71,7 +84,7 @@ def test_rotateby_custom_point(rotate_universes, point): trans = trans_u.trajectory.ts ref = ref_u.trajectory.ts vector = [1, 0, 0] - pos = point.reshape(3, ) + pos = point.reshape(3) angle = 90 matrix = rotation_matrix(np.deg2rad(angle), vector, pos) ref_u.atoms.transform(matrix) @@ -79,9 +92,8 @@ def test_rotateby_custom_point(rotate_universes, point): assert_array_almost_equal(transformed.positions, ref.positions, decimal=6) -@pytest.mark.parametrize('vector', ( - np.asarray([1, 0, 0]), - np.asarray([[1, 0, 0]])) +@pytest.mark.parametrize( + "vector", (np.asarray([1, 0, 0]), np.asarray([[1, 0, 0]])) ) def test_rotateby_vector(rotate_universes, vector): # what happens when we use a custom point for the axis of rotation? @@ -91,7 +103,7 @@ def test_rotateby_vector(rotate_universes, vector): ref = ref_u.trajectory.ts point = [0, 0, 0] angle = 90 - vec = vector.reshape(3, ) + vec = vector.reshape(3) matrix = rotation_matrix(np.deg2rad(angle), vec, point) ref_u.atoms.transform(matrix) transformed = rotateby(angle, vector, point=point)(trans) @@ -105,13 +117,13 @@ def test_rotateby_atomgroup_cog_nopbc(rotate_universes): trans_u = rotate_universes[1] trans = trans_u.trajectory.ts ref = ref_u.trajectory.ts - center_pos = [6,7,8] - vector = [1,0,0] + center_pos = [6, 7, 8] + vector = [1, 0, 0] angle = 90 matrix = rotation_matrix(np.deg2rad(angle), vector, center_pos) ref_u.atoms.transform(matrix) selection = trans_u.residues[0].atoms - transformed = rotateby(angle, vector, ag=selection, weights=None)(trans) + transformed = rotateby(angle, vector, ag=selection, weights=None)(trans) assert_array_almost_equal(transformed.positions, ref.positions, decimal=6) @@ -122,16 +134,16 @@ def test_rotateby_atomgroup_com_nopbc(rotate_universes): trans_u = rotate_universes[1] trans = trans_u.trajectory.ts ref = ref_u.trajectory.ts - vector = [1,0,0] + vector = [1, 0, 0] angle = 90 selection = trans_u.residues[0].atoms center_pos = selection.center_of_mass() matrix = rotation_matrix(np.deg2rad(angle), vector, center_pos) ref_u.atoms.transform(matrix) - transformed = rotateby(angle, vector, ag=selection, weights='mass')(trans) + transformed = rotateby(angle, vector, ag=selection, weights="mass")(trans) assert_array_almost_equal(transformed.positions, ref.positions, decimal=6) - + def test_rotateby_atomgroup_cog_pbc(rotate_universes): # what happens when we rotate arround the center of geometry of a residue # with pbc? @@ -139,13 +151,15 @@ def test_rotateby_atomgroup_cog_pbc(rotate_universes): trans_u = rotate_universes[1] trans = trans_u.trajectory.ts ref = ref_u.trajectory.ts - vector = [1,0,0] + vector = [1, 0, 0] angle = 90 selection = trans_u.residues[0].atoms center_pos = selection.center_of_geometry(pbc=True) matrix = rotation_matrix(np.deg2rad(angle), vector, center_pos) ref_u.atoms.transform(matrix) - transformed = rotateby(angle, vector, ag=selection, weights=None, wrap=True)(trans) + transformed = rotateby( + angle, vector, ag=selection, weights=None, wrap=True + )(trans) assert_array_almost_equal(transformed.positions, ref.positions, decimal=6) @@ -156,25 +170,30 @@ def test_rotateby_atomgroup_com_pbc(rotate_universes): trans_u = rotate_universes[1] trans = trans_u.trajectory.ts ref = ref_u.trajectory.ts - vector = [1,0,0] + vector = [1, 0, 0] angle = 90 selection = trans_u.residues[0].atoms center_pos = selection.center_of_mass(pbc=True) matrix = rotation_matrix(np.deg2rad(angle), vector, center_pos) ref_u.atoms.transform(matrix) - transformed = rotateby(angle, vector, ag=selection, weights='mass', wrap=True)(trans) + transformed = rotateby( + angle, vector, ag=selection, weights="mass", wrap=True + )(trans) assert_array_almost_equal(transformed.positions, ref.positions, decimal=6) -@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) +@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_rotateby_bad_ag(rotate_universes, ag): # this universe as a box size zero @@ -184,19 +203,22 @@ def test_rotateby_bad_ag(rotate_universes, ag): angle = 90 vector = [0, 0, 1] bad_ag = 1 - with pytest.raises(ValueError): - rotateby(angle, vector, ag = bad_ag)(ts) - - -@pytest.mark.parametrize('point', ( - [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]]), - 'thisisnotapoint', - 1) + with pytest.raises(ValueError): + rotateby(angle, vector, ag=bad_ag)(ts) + + +@pytest.mark.parametrize( + "point", + ( + [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]]), + "thisisnotapoint", + 1, + ), ) def test_rotateby_bad_point(rotate_universes, point): # this universe as a box size zero @@ -205,19 +227,22 @@ def test_rotateby_bad_point(rotate_universes, point): angle = 90 vector = [0, 0, 1] bad_position = point - with pytest.raises(ValueError): + with pytest.raises(ValueError): rotateby(angle, vector, point=bad_position)(ts) -@pytest.mark.parametrize('direction', ( - [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]]), - 'thisisnotadirection', - 1) +@pytest.mark.parametrize( + "direction", + ( + [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]]), + "thisisnotadirection", + 1, + ), ) def test_rotateby_bad_direction(rotate_universes, direction): # this universe as a box size zero @@ -225,11 +250,11 @@ def test_rotateby_bad_direction(rotate_universes, direction): # what if the box is in the wrong format? angle = 90 point = [0, 0, 0] - with pytest.raises(ValueError): + with pytest.raises(ValueError): rotateby(angle, direction, point=point)(ts) -def test_rotateby_bad_pbc(rotate_universes): +def test_rotateby_bad_pbc(rotate_universes): # this universe as a box size zero ts = rotate_universes[0].trajectory.ts ag = rotate_universes[0].residues[0].atoms @@ -237,18 +262,21 @@ def test_rotateby_bad_pbc(rotate_universes): # if yes it should raise an exception for boxes that are zero in size vector = [1, 0, 0] angle = 90 - with pytest.raises(ValueError): - rotateby(angle, vector, ag = ag, wrap=True)(ts) - - -@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]])) + with pytest.raises(ValueError): + rotateby(angle, vector, ag=ag, wrap=True)(ts) + + +@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_rotateby_bad_weights(rotate_universes, weights): # this universe as a box size zero @@ -258,11 +286,11 @@ def test_rotateby_bad_weights(rotate_universes, weights): angle = 90 vector = [0, 0, 1] bad_weights = " " - with pytest.raises(TypeError): - rotateby(angle, vector, ag = ag, weights=bad_weights)(ts) + with pytest.raises(TypeError): + rotateby(angle, vector, ag=ag, weights=bad_weights)(ts) + - -def test_rotateby_no_masses(rotate_universes): +def test_rotateby_no_masses(rotate_universes): # this universe as a box size zero ts = rotate_universes[0].trajectory.ts ag = rotate_universes[0].residues[0].atoms @@ -270,8 +298,8 @@ def test_rotateby_no_masses(rotate_universes): angle = 90 vector = [0, 0, 1] bad_center = "mass" - with pytest.raises(TypeError): - rotateby(angle, vector, ag = ag, weights=bad_center)(ts) + with pytest.raises(TypeError): + rotateby(angle, vector, ag=ag, weights=bad_center)(ts) def test_rotateby_no_args(rotate_universes): @@ -281,5 +309,5 @@ def test_rotateby_no_args(rotate_universes): vector = [0, 0, 1] # if no point or AtomGroup are passed to the function # it should raise a ValueError - with pytest.raises(ValueError): + with pytest.raises(ValueError): rotateby(angle, vector)(ts) diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index d8bde95009..ccb431f3c5 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -1,4 +1,4 @@ -#-*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- +# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 fileencoding=utf-8 # # MDAnalysis --- https://www.mdanalysis.org @@ -35,9 +35,11 @@ def translate_universes(): # create the Universe objects for the tests # this universe has no masses and some tests need it as such reference = make_Universe(trajectory=True) - transformed = make_Universe(['masses'], trajectory=True) - transformed.trajectory.ts.dimensions = np.array([372., 373., 374., 90, 90, 90]) - + transformed = make_Universe(["masses"], trajectory=True) + transformed.trajectory.ts.dimensions = np.array( + [372.0, 373.0, 374.0, 90, 90, 90] + ) + return reference, transformed @@ -50,13 +52,16 @@ def test_translate_coords(translate_universes): assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -@pytest.mark.parametrize('vector', ( - [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]])) +@pytest.mark.parametrize( + "vector", + ( + [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_translate_vector(translate_universes, vector): # what happens if the vector argument is of wrong size? @@ -64,16 +69,18 @@ def test_translate_vector(translate_universes, vector): with pytest.raises(ValueError): translate(vector)(ts) - + def test_translate_transformations_api(translate_universes): - # test if the translate transformation works when using the + # test if the translate transformation works when using the # on-the-fly transformations API ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts vector = np.float32([1, 2, 3]) ref.positions += vector trans_u.trajectory.add_transformations(translate(vector)) - assert_array_almost_equal(trans_u.trajectory.ts.positions, ref.positions, decimal=6) + assert_array_almost_equal( + trans_u.trajectory.ts.positions, ref.positions, decimal=6 + ) def test_center_in_box_bad_ag(translate_universes): @@ -81,33 +88,36 @@ 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(ValueError): center_in_box(bad_ag)(ts) -@pytest.mark.parametrize('point', ( - [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]])) +@pytest.mark.parametrize( + "point", + ( + [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_box_bad_point(translate_universes, point): ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms # what if the box is in the wrong format? - with pytest.raises(ValueError): + with pytest.raises(ValueError): center_in_box(ag, point=point)(ts) - -def test_center_in_box_bad_pbc(translate_universes): + +def test_center_in_box_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 - with pytest.raises(ValueError): + with pytest.raises(ValueError): center_in_box(ag, wrap=True)(ts) @@ -117,11 +127,11 @@ def test_center_in_box_bad_center(translate_universes): ag = translate_universes[0].residues[0].atoms # what if a wrong center type name is passed? bad_center = " " - with pytest.raises(ValueError): + with pytest.raises(ValueError): center_in_box(ag, center=bad_center)(ts) -def test_center_in_box_no_masses(translate_universes): +def test_center_in_box_no_masses(translate_universes): # this universe has no masses ts = translate_universes[0].trajectory.ts ag = translate_universes[0].residues[0].atoms @@ -137,7 +147,7 @@ def test_center_in_box_coords_no_options(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.]) + box_center = np.float32([186.0, 186.5, 187.0]) ref.positions += box_center - ref_center ag = trans_u.residues[0].atoms trans = center_in_box(ag)(trans_u.trajectory.ts) @@ -149,28 +159,28 @@ def test_center_in_box_coords_with_pbc(translate_universes): # 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.] + trans_u.dimensions = [363.0, 364.0, 365.0, 90.0, 90.0, 90.0] ag = trans_u.residues[24].atoms - box_center = np.float32([181.5, 182., 182.5]) - ref_center = np.float32([75.6, 75.8, 76.]) + box_center = np.float32([181.5, 182.0, 182.5]) + ref_center = np.float32([75.6, 75.8, 76.0]) ref.positions += box_center - ref_center trans = center_in_box(ag, wrap=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): +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.]) + box_center = np.float32([186.0, 186.5, 187.0]) ref_center = ag.center_of_mass() ref.positions += box_center - ref_center trans = center_in_box(ag, center="mass")(trans_u.trajectory.ts) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) -def test_center_in_box_coords_with_box(translate_universes): +def test_center_in_box_coords_with_box(translate_universes): # using masses for calculating the center of the atomgroup ref_u, trans_u = translate_universes ref = ref_u.trajectory.ts @@ -193,18 +203,22 @@ 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="mass", wrap=True, point=newpoint)( + trans_u.trajectory.ts + ) assert_array_almost_equal(trans.positions, ref.positions, decimal=6) def test_center_transformations_api(translate_universes): - # test if the translate transformation works when using the + # test if the translate transformation works when using the # on-the-fly transformations API 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.]) + box_center = np.float32([186.0, 186.5, 187.0]) ref.positions += box_center - ref_center 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) + assert_array_almost_equal( + trans_u.trajectory.ts.positions, ref.positions, decimal=6 + ) diff --git a/testsuite/MDAnalysisTests/transformations/test_wrap.py b/testsuite/MDAnalysisTests/transformations/test_wrap.py index a9fa34a36a..a3439fb95c 100644 --- a/testsuite/MDAnalysisTests/transformations/test_wrap.py +++ b/testsuite/MDAnalysisTests/transformations/test_wrap.py @@ -1,4 +1,4 @@ -#-*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- +# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 fileencoding=utf-8 # # MDAnalysis --- https://www.mdanalysis.org @@ -39,7 +39,7 @@ def wrap_universes(): transformed = mda.Universe(fullerene) transformed.dimensions = np.asarray([10, 10, 10, 90, 90, 90], np.float32) transformed.atoms.wrap() - + return reference, transformed @@ -52,30 +52,33 @@ def compound_wrap_universes(): reference = mda.Universe(TPR, GRO) # wrap the atoms back into the unit cell # in this coordinate file only the protein - # is broken across PBC however the system + # is broken across PBC however the system # shape is not the same as the unit cell make_whole(reference.select_atoms("protein")) make_whole(transformed.select_atoms("protein")) - + return transformed, reference -@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) +@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_wrap_bad_ag(wrap_universes, ag): # this universe has a box size zero ts = wrap_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? bad_ag = ag - with pytest.raises(AttributeError): + with pytest.raises(AttributeError): wrap(bad_ag)(ts) @@ -85,45 +88,53 @@ def test_wrap_no_options(wrap_universes): trans, ref = wrap_universes trans.dimensions = ref.dimensions wrap(trans.atoms)(trans.trajectory.ts) - assert_array_almost_equal(trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6) + assert_array_almost_equal( + trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6 + ) -@pytest.mark.parametrize('compound', ( - "group", - "residues", - "segments", - "fragments") +@pytest.mark.parametrize( + "compound", ("group", "residues", "segments", "fragments") ) def test_wrap_with_compounds(compound_wrap_universes, compound): - trans, ref= compound_wrap_universes + trans, ref = compound_wrap_universes ref.select_atoms("not resname SOL").wrap(compound=compound) - wrap(trans.select_atoms("not resname SOL"), compound=compound)(trans.trajectory.ts) - assert_array_almost_equal(trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6) + wrap(trans.select_atoms("not resname SOL"), compound=compound)( + trans.trajectory.ts + ) + assert_array_almost_equal( + trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6 + ) def test_wrap_api(wrap_universes): trans, ref = wrap_universes trans.dimensions = ref.dimensions trans.trajectory.add_transformations(wrap(trans.atoms)) - assert_array_almost_equal(trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6) - - -@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) + assert_array_almost_equal( + trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6 + ) + + +@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_unwrap_bad_ag(wrap_universes, ag): # this universe has a box size zero ts = wrap_universes[0].trajectory.ts # what happens if something other than an AtomGroup is given? bad_ag = ag - with pytest.raises(AttributeError): + with pytest.raises(AttributeError): unwrap(bad_ag)(ts) @@ -131,11 +142,15 @@ def test_unwrap(wrap_universes): ref, trans = wrap_universes # after rebuild the trans molecule it should match the reference unwrap(trans.atoms)(trans.trajectory.ts) - assert_array_almost_equal(trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6) + assert_array_almost_equal( + trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6 + ) def test_unwrap_api(wrap_universes): ref, trans = wrap_universes # after rebuild the trans molecule it should match the reference trans.trajectory.add_transformations(unwrap(trans.atoms)) - assert_array_almost_equal(trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6) + assert_array_almost_equal( + trans.trajectory.ts.positions, ref.trajectory.ts.positions, decimal=6 + ) diff --git a/testsuite/pyproject.toml b/testsuite/pyproject.toml index 7f42a28fef..b53e8782e1 100644 --- a/testsuite/pyproject.toml +++ b/testsuite/pyproject.toml @@ -160,6 +160,7 @@ include = ''' ( setup\.py | MDAnalysisTests/auxiliary/.*\.py +| MDAnalysisTests/transformations/.*\.py ) ''' extend-exclude = '__pycache__'