From 60973ba8c8e4277aa1ba1185f3d147ef1b7bcea9 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Fri, 13 Jun 2025 17:43:41 -0400 Subject: [PATCH 01/26] Inditial addition of code to calculate time-averaged msd for non-linear dump --- package/MDAnalysis/analysis/msd.py | 81 +++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 8d0e7a39e1..1746a6c15e 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -263,7 +263,17 @@ del Doi + class EinsteinMSD(AnalysisBase): + + @staticmethod + def is_linear(sequence): # This function is to check if the timesteps in the array is linear or not! If it's linear default MDA code will carry-out other wise the modified code carries! + if len(sequence) < 2: + return True + step = sequence[1] - sequence[0] + return all(sequence[i+1] - sequence[i] == step for i in range(len(sequence) - 1)) + + r"""Class to calculate Mean Squared Displacement by the Einstein relation. Parameters @@ -386,9 +396,13 @@ def _conclude(self): if self.fft: self._conclude_fft() else: - self._conclude_simple() + if self.is_linear([ts.time for ts in self._trajectory]): + self._conclude_simple() + else: + self._conclude_modified() # New modified code def _conclude_simple(self): + print("The Dump file has linear time spacing") # optional comment I wrote to check if the is_linear flag working correctly r"""Calculates the MSD via the simple "windowed" algorithm.""" lagtimes = np.arange(1, self.n_frames) positions = self._position_array.astype(np.float64) @@ -421,3 +435,68 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. positions[:, n, :] ) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) + + + + + + + # New function to calculate in the following + # + # Note: This function is generalized for non-linear dumps. + # Moreover, if you use this function to calculate for linear timedump this gives same result as '_conclude_simple' which is implemented in the default version. + # So, I believe this following algorithm can potentially be used to calculate time-averaged msd in future. + # For now it only executes when the dump is non-linear. + # It is tested with a .dump file of a Coarse Grained system of single type + + def _conclude_modified(self): + from collections import defaultdict + import matplotlib.pyplot as plt + print("The Dump file has non-linear time spacing") + + dump_times = [ts.time for ts in self._trajectory] + # print(dump_times) + n_frames = len(dump_times) + n_atoms = self.n_particles + positions = np.zeros((n_frames, n_atoms, 3)) + positions = self._position_array.astype(np.float64) + + msd_dict = defaultdict(list) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} + + # Looping over all the frames as if the referenced gets shifted frame to frame + for i in range(n_frames): + for j in range(i + 1, n_frames): + delta_t = dump_times[j] - dump_times[i] + + # Compute displacement and squared displacement + disp = positions[j] - positions[i] + squared_disp = np.sum(disp ** 2, axis=1) + msd = np.mean(squared_disp) + + # Store MSD under corresponding Δt + msd_dict[delta_t].append(msd) + + print(msd_dict) + msd_dict[0] = [0] + + # Prepare averaged results + delta_t_values = [] + avg_msds = [] + for delta_t in sorted(msd_dict.keys()): + msd_list = msd_dict[delta_t] + avg_msd = np.mean(msd_list) + delta_t_values.append(delta_t) + avg_msds.append(avg_msd) + print(f"Δt = {delta_t}: Averaged MSD = {avg_msd} (from {len(msd_list)} pairs)") + + # Plot Δt vs averaged MSD # Optional + plt.figure(figsize=(8, 5)) + plt.plot(delta_t_values, avg_msds,marker='o', linestyle='-', label='Averaged MSD') + + plt.xlabel('Δt (Time Difference)') + plt.ylabel('Mean Squared Displacement (MSD)') + plt.title('MSD Averaged Over Frame Pairs with Same Δt') + plt.grid(True) + plt.legend() + plt.tight_layout() + plt.show() From 0dc3db19adb6702cef35cfd881197e38806dac39 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Fri, 13 Jun 2025 19:23:43 -0400 Subject: [PATCH 02/26] updated_documentation_v1_plots_removed --- package/MDAnalysis/analysis/msd.py | 55 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 1746a6c15e..85935519b4 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -1,3 +1,25 @@ +######## Documentation +# +# Issue: The default '_conclude_simple()' function previously calculated time-averaged mean squared displacement considering linear timespacing between the frames even when a dump file with non-linear timestep gap is provided +# +# Modified by Sirsha Ganguly +# +# Modification: +# '_conclude_modified()' is the new function added to calculate time-averaged mean squared displacement of non-linear dumps + # Note: This new function is generalized for non-linear dumps. + # Moreover, if you use this function to calculate for linear timedump this gives same result as '_conclude_simple()' which is implemented in the default version. + # So, I believe the algorithm in '_conclude_modified()' can potentially be used to calculate time-averaged msd in future. + # For now it only executes when the dump is non-linear. [ This is determined by the added function is_linear() ] + # It is tested with a .dump file of a Coarse Grained system of single type +# +# General Algorithm of '_conclude_modified()' to calculate time-averaged msd: + # It creates a dictionary/hash-map with the key being the time difference between the frames (Delta t) and value being a list containing the frame to frame MSD values [msd1, msd2, .....] for that particular Delta t + # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} + # The reference frame is changed with each iteration and each time a new Key (i.e, Delta t) is found it is appended in the dictionary/hash-map + # If a duplicate Delta_t is found it is added to the value (msd list) of that specefic Key in the dictionary/hash-map + # Lastly in the dictionary/hash-map for each Delta_t the msd values inside the list are averaged +# + # -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 # @@ -402,7 +424,6 @@ def _conclude(self): self._conclude_modified() # New modified code def _conclude_simple(self): - print("The Dump file has linear time spacing") # optional comment I wrote to check if the is_linear flag working correctly r"""Calculates the MSD via the simple "windowed" algorithm.""" lagtimes = np.arange(1, self.n_frames) positions = self._position_array.astype(np.float64) @@ -437,21 +458,8 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. self.results.timeseries = self.results.msds_by_particle.mean(axis=1) - - - - - # New function to calculate in the following - # - # Note: This function is generalized for non-linear dumps. - # Moreover, if you use this function to calculate for linear timedump this gives same result as '_conclude_simple' which is implemented in the default version. - # So, I believe this following algorithm can potentially be used to calculate time-averaged msd in future. - # For now it only executes when the dump is non-linear. - # It is tested with a .dump file of a Coarse Grained system of single type - def _conclude_modified(self): from collections import defaultdict - import matplotlib.pyplot as plt print("The Dump file has non-linear time spacing") dump_times = [ts.time for ts in self._trajectory] @@ -476,7 +484,6 @@ def _conclude_modified(self): # Store MSD under corresponding Δt msd_dict[delta_t].append(msd) - print(msd_dict) msd_dict[0] = [0] # Prepare averaged results @@ -487,16 +494,8 @@ def _conclude_modified(self): avg_msd = np.mean(msd_list) delta_t_values.append(delta_t) avg_msds.append(avg_msd) - print(f"Δt = {delta_t}: Averaged MSD = {avg_msd} (from {len(msd_list)} pairs)") - - # Plot Δt vs averaged MSD # Optional - plt.figure(figsize=(8, 5)) - plt.plot(delta_t_values, avg_msds,marker='o', linestyle='-', label='Averaged MSD') - - plt.xlabel('Δt (Time Difference)') - plt.ylabel('Mean Squared Displacement (MSD)') - plt.title('MSD Averaged Over Frame Pairs with Same Δt') - plt.grid(True) - plt.legend() - plt.tight_layout() - plt.show() + + self.results.timeseries = delta_t_values + self.results.msds_by_particle = avg_msds + + # self.results.timeseries = self.results.msds_by_particle.mean(axis=1) \ No newline at end of file From f6f55a10846ff7defc45c874be0fdcc76a8500d8 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Sun, 15 Jun 2025 14:07:24 -0400 Subject: [PATCH 03/26] Added_name_in_the_package/AUTHORS --- package/AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/AUTHORS b/package/AUTHORS index 8c94548ad2..61eadbaf75 100644 --- a/package/AUTHORS +++ b/package/AUTHORS @@ -259,7 +259,7 @@ Chronological list of authors - Tulga-Erdene Sodjargal - Gareth Elliott - Marc Schuh - + - Sirsha Ganguly External code ------------- From e363635473810570b3b565a175b47379c52e21ea Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Mon, 30 Jun 2025 18:35:54 -0400 Subject: [PATCH 04/26] addressed_review_comments_mainly_removed_linearity_check --- package/MDAnalysis/analysis/msd.py | 57 ++++++------------------------ 1 file changed, 11 insertions(+), 46 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 85935519b4..afcaaa1f6d 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -1,25 +1,3 @@ -######## Documentation -# -# Issue: The default '_conclude_simple()' function previously calculated time-averaged mean squared displacement considering linear timespacing between the frames even when a dump file with non-linear timestep gap is provided -# -# Modified by Sirsha Ganguly -# -# Modification: -# '_conclude_modified()' is the new function added to calculate time-averaged mean squared displacement of non-linear dumps - # Note: This new function is generalized for non-linear dumps. - # Moreover, if you use this function to calculate for linear timedump this gives same result as '_conclude_simple()' which is implemented in the default version. - # So, I believe the algorithm in '_conclude_modified()' can potentially be used to calculate time-averaged msd in future. - # For now it only executes when the dump is non-linear. [ This is determined by the added function is_linear() ] - # It is tested with a .dump file of a Coarse Grained system of single type -# -# General Algorithm of '_conclude_modified()' to calculate time-averaged msd: - # It creates a dictionary/hash-map with the key being the time difference between the frames (Delta t) and value being a list containing the frame to frame MSD values [msd1, msd2, .....] for that particular Delta t - # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} - # The reference frame is changed with each iteration and each time a new Key (i.e, Delta t) is found it is appended in the dictionary/hash-map - # If a duplicate Delta_t is found it is added to the value (msd list) of that specefic Key in the dictionary/hash-map - # Lastly in the dictionary/hash-map for each Delta_t the msd values inside the list are averaged -# - # -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 # @@ -267,6 +245,7 @@ from .base import AnalysisBase from ..core import groups from tqdm import tqdm +import collections logger = logging.getLogger("MDAnalysis.analysis.msd") @@ -288,14 +267,6 @@ class EinsteinMSD(AnalysisBase): - @staticmethod - def is_linear(sequence): # This function is to check if the timesteps in the array is linear or not! If it's linear default MDA code will carry-out other wise the modified code carries! - if len(sequence) < 2: - return True - step = sequence[1] - sequence[0] - return all(sequence[i+1] - sequence[i] == step for i in range(len(sequence) - 1)) - - r"""Class to calculate Mean Squared Displacement by the Einstein relation. Parameters @@ -333,7 +304,7 @@ def is_linear(sequence): # This function is to check if the timesteps in the arr .. versionadded:: 2.0.0 """ - def __init__(self, u, select="all", msd_type="xyz", fft=True, **kwargs): + def __init__(self, u, select="all", msd_type="xyz", fft=True, non_linear = False, **kwargs): r""" Parameters ---------- @@ -361,6 +332,7 @@ def __init__(self, u, select="all", msd_type="xyz", fft=True, **kwargs): self.msd_type = msd_type self._parse_msd_type() self.fft = fft + self.non_linear = non_linear # local self.ag = u.select_atoms(self.select) @@ -415,13 +387,12 @@ def _single_frame(self): ] def _conclude(self): - if self.fft: + if self.fft == True: self._conclude_fft() - else: - if self.is_linear([ts.time for ts in self._trajectory]): - self._conclude_simple() - else: - self._conclude_modified() # New modified code + elif self.non_linear != True: + self._conclude_simple() + elif self.non_linear: + self._conclude_non_linear() def _conclude_simple(self): r"""Calculates the MSD via the simple "windowed" algorithm.""" @@ -458,18 +429,14 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. self.results.timeseries = self.results.msds_by_particle.mean(axis=1) - def _conclude_modified(self): - from collections import defaultdict - print("The Dump file has non-linear time spacing") + def _conclude_non_linear(self): dump_times = [ts.time for ts in self._trajectory] - # print(dump_times) n_frames = len(dump_times) n_atoms = self.n_particles - positions = np.zeros((n_frames, n_atoms, 3)) positions = self._position_array.astype(np.float64) - msd_dict = defaultdict(list) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} + msd_dict = collections.defaultdict(list) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} # Looping over all the frames as if the referenced gets shifted frame to frame for i in range(n_frames): @@ -496,6 +463,4 @@ def _conclude_modified(self): avg_msds.append(avg_msd) self.results.timeseries = delta_t_values - self.results.msds_by_particle = avg_msds - - # self.results.timeseries = self.results.msds_by_particle.mean(axis=1) \ No newline at end of file + self.results.msds_by_particle = avg_msds \ No newline at end of file From 5aa09ca4f542f4d6fa8596fcd78b7ae6b5b629d2 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Mon, 14 Jul 2025 15:06:08 -0400 Subject: [PATCH 05/26] added results delta t values --- package/MDAnalysis/analysis/msd.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index afcaaa1f6d..bbbba919cf 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -342,6 +342,7 @@ def __init__(self, u, select="all", msd_type="xyz", fft=True, non_linear = False # result self.results.msds_by_particle = None self.results.timeseries = None + self.results.delta_t_values = None def _prepare(self): # self.n_frames only available here @@ -431,8 +432,8 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. def _conclude_non_linear(self): - dump_times = [ts.time for ts in self._trajectory] - n_frames = len(dump_times) + dump_times = self.times + n_frames = self.n_frames n_atoms = self.n_particles positions = self._position_array.astype(np.float64) @@ -462,5 +463,5 @@ def _conclude_non_linear(self): delta_t_values.append(delta_t) avg_msds.append(avg_msd) - self.results.timeseries = delta_t_values - self.results.msds_by_particle = avg_msds \ No newline at end of file + self.results.timeseries = np.array(avg_msds, dtype=np.float64) + self.results.delta_t_values = np.array(delta_t_values, dtype=np.float64) \ No newline at end of file From 871faa2ae3e289a7538c981a47bb931a2bbeaa29 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Tue, 22 Jul 2025 12:14:41 -0400 Subject: [PATCH 06/26] initial test added changed changelog and docs --- package/CHANGELOG | 5 + package/MDAnalysis/analysis/msd.py | 63 +++-- .../MDAnalysisTests/analysis/test_msd.py | 169 +++++++++-- .../custom_non_linear/test_non_linear.dump | 264 ++++++++++++++++++ testsuite/MDAnalysisTests/datafiles.py | 1 + 5 files changed, 455 insertions(+), 47 deletions(-) create mode 100644 testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump diff --git a/package/CHANGELOG b/package/CHANGELOG index ecf87e8915..e5dce0d11c 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -63,6 +63,11 @@ Enhancements (PR #5038) * Moved distopia checking function to common import location in MDAnalysisTest.util (PR #5038) + * Added new method '_conclude_non_linear` to calculate time-averaged + mean square displacement in `package/MDAnalysis/analysis/msd.py`, + new bool keyword argument `non_linear=True` under `EinsteinMSD` + enables execution of this method. + (Issue #5028, PR #5066) Changes * Refactored the RDKit converter code to move the inferring code in a separate diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index bbbba919cf..e354dc0ac4 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -173,7 +173,7 @@ start_index = int(start_time/timestep) end_time = 60 linear_model = linregress(lagtimes[start_index:end_index], - msd[start_index:end_index]) + msd[start_index:end_index]) slope = linear_model.slope error = linear_model.stderr # dim_fac is 3 as we computed a 3D msd with 'xyz' @@ -264,9 +264,7 @@ del Doi - class EinsteinMSD(AnalysisBase): - r"""Class to calculate Mean Squared Displacement by the Einstein relation. Parameters @@ -284,6 +282,10 @@ class EinsteinMSD(AnalysisBase): the MSD. Otherwise, use the simple "windowed" algorithm. The tidynamics package is required for `fft=True`. Defaults to ``True``. + non_linear : bool + If ``True``, calculates MSD for trajectory where frames are + non-linearly dumped. To use this set `fft=False`. + Defaults to ``False``. Attributes ---------- @@ -293,6 +295,8 @@ class EinsteinMSD(AnalysisBase): The averaged MSD over all the particles with respect to lag-time. results.msds_by_particle : :class:`numpy.ndarray` The MSD of each individual particle with respect to lag-time. + results.delta_t_values : :class:`numpy.ndarray` + Array of unique Δt (time differences) at which time-averaged MSD values are computed. ag : :class:`AtomGroup` The :class:`AtomGroup` resulting from your selection n_frames : int @@ -301,10 +305,12 @@ class EinsteinMSD(AnalysisBase): Number of particles MSD was calculated over. - .. versionadded:: 2.0.0 + .. versionadded:: 2.10.0 """ - def __init__(self, u, select="all", msd_type="xyz", fft=True, non_linear = False, **kwargs): + def __init__( + self, u, select="all", msd_type="xyz", fft=True, non_linear=False, **kwargs + ): r""" Parameters ---------- @@ -319,11 +325,12 @@ def __init__(self, u, select="all", msd_type="xyz", fft=True, non_linear = False If ``True``, uses a fast FFT based algorithm for computation of the MSD. Otherwise, use the simple "windowed" algorithm. The tidynamics package is required for `fft=True`. + non_linear : bool + If ``True``, calculates MSD for trajectory where frames are + non-linearly dumped. To use this set `fft=False`. """ if isinstance(u, groups.UpdatingAtomGroup): - raise TypeError( - "UpdatingAtomGroups are not valid for MSD " "computation" - ) + raise TypeError("UpdatingAtomGroups are not valid for MSD " "computation") super(EinsteinMSD, self).__init__(u.universe.trajectory, **kwargs) @@ -347,12 +354,8 @@ def __init__(self, u, select="all", msd_type="xyz", fft=True, non_linear = False def _prepare(self): # self.n_frames only available here # these need to be zeroed prior to each run() call - self.results.msds_by_particle = np.zeros( - (self.n_frames, self.n_particles) - ) - self._position_array = np.zeros( - (self.n_frames, self.n_particles, self.dim_fac) - ) + self.results.msds_by_particle = np.zeros((self.n_frames, self.n_particles)) + self._position_array = np.zeros((self.n_frames, self.n_particles, self.dim_fac)) # self.results.timeseries not set here def _parse_msd_type(self): @@ -383,17 +386,16 @@ def _single_frame(self): r"""Constructs array of positions for MSD calculation.""" # shape of position array set here, use span in last dimension # from this point on - self._position_array[self._frame_index] = self.ag.positions[ - :, self._dim - ] + self._position_array[self._frame_index] = self.ag.positions[:, self._dim] def _conclude(self): - if self.fft == True: - self._conclude_fft() - elif self.non_linear != True: - self._conclude_simple() - elif self.non_linear: + if self.non_linear: self._conclude_non_linear() + else: + if self.fft: + self._conclude_fft() + else: + self._conclude_simple() def _conclude_simple(self): r"""Calculates the MSD via the simple "windowed" algorithm.""" @@ -424,20 +426,19 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. positions = self._position_array.astype(np.float64) for n in tqdm(range(self.n_particles)): - self.results.msds_by_particle[:, n] = tidynamics.msd( - positions[:, n, :] - ) + self.results.msds_by_particle[:, n] = tidynamics.msd(positions[:, n, :]) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) - def _conclude_non_linear(self): - + dump_times = self.times n_frames = self.n_frames n_atoms = self.n_particles positions = self._position_array.astype(np.float64) - msd_dict = collections.defaultdict(list) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} + msd_dict = collections.defaultdict( + list + ) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} # Looping over all the frames as if the referenced gets shifted frame to frame for i in range(n_frames): @@ -446,7 +447,7 @@ def _conclude_non_linear(self): # Compute displacement and squared displacement disp = positions[j] - positions[i] - squared_disp = np.sum(disp ** 2, axis=1) + squared_disp = np.sum(disp**2, axis=1) msd = np.mean(squared_disp) # Store MSD under corresponding Δt @@ -462,6 +463,6 @@ def _conclude_non_linear(self): avg_msd = np.mean(msd_list) delta_t_values.append(delta_t) avg_msds.append(avg_msd) - + self.results.timeseries = np.array(avg_msds, dtype=np.float64) - self.results.delta_t_values = np.array(delta_t_values, dtype=np.float64) \ No newline at end of file + self.results.delta_t_values = np.array(delta_t_values, dtype=np.float64) diff --git a/testsuite/MDAnalysisTests/analysis/test_msd.py b/testsuite/MDAnalysisTests/analysis/test_msd.py index 757fe6552c..29435ab470 100644 --- a/testsuite/MDAnalysisTests/analysis/test_msd.py +++ b/testsuite/MDAnalysisTests/analysis/test_msd.py @@ -28,7 +28,13 @@ from numpy.testing import assert_almost_equal, assert_equal import numpy as np -from MDAnalysisTests.datafiles import PSF, DCD, RANDOM_WALK, RANDOM_WALK_TOPO +from MDAnalysisTests.datafiles import ( + PSF, + DCD, + RANDOM_WALK, + RANDOM_WALK_TOPO, + LAMMPSDUMP_non_linear, +) from MDAnalysisTests.util import block_import, import_not_available import pytest @@ -124,9 +130,7 @@ def test_msdtype_error(self, u, SELECTION, msdtype): ("z", 1), ], ) - def test_simple_step_traj_all_dims( - self, step_traj, NSTEP, dim, dim_factor - ): + def test_simple_step_traj_all_dims(self, step_traj, NSTEP, dim, dim_factor): # testing the "simple" algorithm on constant velocity trajectory # should fit the polynomial y=dim_factor*x**2 m_simple = MSD(step_traj, "all", msd_type=dim, fft=False) @@ -146,18 +150,14 @@ def test_simple_step_traj_all_dims( ("z", 1), ], ) - def test_simple_start_stop_step_all_dims( - self, step_traj, NSTEP, dim, dim_factor - ): + def test_simple_start_stop_step_all_dims(self, step_traj, NSTEP, dim, dim_factor): # testing the "simple" algorithm on constant velocity trajectory # test start stop step is working correctly m_simple = MSD(step_traj, "all", msd_type=dim, fft=False) m_simple.run(start=10, stop=1000, step=10) poly = characteristic_poly(NSTEP, dim_factor) # polynomial must take offset start into account - assert_almost_equal( - m_simple.results.timeseries, poly[0:990:10], decimal=4 - ) + assert_almost_equal(m_simple.results.timeseries, poly[0:990:10], decimal=4) def test_random_walk_u_simple(self, random_walk_u): # regress against random_walk test data @@ -252,18 +252,14 @@ def test_fft_step_traj_all_dims(self, step_traj, NSTEP, dim, dim_factor): ("z", 1), ], ) - def test_fft_start_stop_step_all_dims( - self, step_traj, NSTEP, dim, dim_factor - ): + def test_fft_start_stop_step_all_dims(self, step_traj, NSTEP, dim, dim_factor): # testing the fft algorithm on constant velocity trajectory # test start stop step is working correctly m_simple = MSD(step_traj, "all", msd_type=dim, fft=True) m_simple.run(start=10, stop=1000, step=10) poly = characteristic_poly(NSTEP, dim_factor) # polynomial must take offset start into account - assert_almost_equal( - m_simple.results.timeseries, poly[0:990:10], decimal=3 - ) + assert_almost_equal(m_simple.results.timeseries, poly[0:990:10], decimal=3) def test_random_walk_u_fft(self, random_walk_u): # regress against random_walk test data @@ -272,3 +268,144 @@ def test_random_walk_u_fft(self, random_walk_u): norm = np.linalg.norm(msd_rw.results.timeseries) val = 3932.39927487146 assert_almost_equal(norm, val, decimal=5) + + +def test_msd_non_linear(): + u = mda.Universe(LAMMPSDUMP_non_linear, format="LAMMPSDUMP") + + msd = MSD(u, select="all", msd_type="xyz", non_linear=True) + msd.run() + + result_msd = msd.results.timeseries + result_delta_t = msd.results.delta_t_values + + assert result_msd.ndim == 1 + assert result_msd.shape[0] > 0 + + assert result_delta_t.ndim == 1 + assert result_delta_t.shape[0] > 0 + + expected_msd = np.array( + [ + 0.00000000e00, + 7.70976963e-05, + 2.90842662e-04, + 6.55040347e-04, + 1.20610926e-03, + 2.52547250e-03, + 3.31645965e-03, + 5.38852795e-03, + 1.01941562e-02, + 1.24745603e-02, + 1.35380300e-02, + 1.57475527e-02, + 2.85165801e-02, + 3.50591021e-02, + 3.81292797e-02, + 3.96176470e-02, + 3.83551274e-02, + 5.51041371e-02, + 5.95049433e-02, + 6.07026502e-02, + 6.14434181e-02, + 6.19512436e-02, + 6.61293773e-02, + 9.46607497e-02, + 1.01300585e-01, + 9.96583811e-02, + 9.81112279e-02, + 9.72780657e-02, + 9.69221886e-02, + 1.29442431e-01, + 1.80752226e-01, + 1.86358673e-01, + 1.98140564e-01, + 2.00603000e-01, + 1.99094789e-01, + 1.97272787e-01, + 1.96156023e-01, + 2.67664446e-01, + 4.50987076e-01, + 4.02344442e-01, + 3.91458056e-01, + 4.10370922e-01, + 4.22997445e-01, + 4.26217251e-01, + 4.26484034e-01, + 4.26360794e-01, + 6.91315347e-01, + 9.94317423e-01, + 1.19622365e00, + 1.04919180e00, + 1.06437594e00, + 1.09426432e00, + 1.10194082e00, + 1.10275424e00, + 1.10383947e00, + 1.10493159e00, + ] + ) + + expected_delta_t = np.array( + [ + 0.000e00, + 1.000e00, + 2.000e00, + 3.000e00, + 4.000e00, + 6.000e00, + 7.000e00, + 8.000e00, + 1.200e01, + 1.400e01, + 1.500e01, + 1.600e01, + 2.400e01, + 2.800e01, + 3.000e01, + 3.100e01, + 3.200e01, + 4.800e01, + 5.600e01, + 6.000e01, + 6.200e01, + 6.300e01, + 6.400e01, + 9.600e01, + 1.120e02, + 1.200e02, + 1.240e02, + 1.260e02, + 1.270e02, + 1.280e02, + 1.920e02, + 2.240e02, + 2.400e02, + 2.480e02, + 2.520e02, + 2.540e02, + 2.550e02, + 2.560e02, + 3.840e02, + 4.480e02, + 4.800e02, + 4.960e02, + 5.040e02, + 5.080e02, + 5.100e02, + 5.110e02, + 5.120e02, + 7.680e02, + 8.960e02, + 9.600e02, + 9.920e02, + 1.008e03, + 1.016e03, + 1.020e03, + 1.022e03, + 1.023e03, + ] + ) + + np.testing.assert_allclose(result_msd, expected_msd, rtol=1e-5) + np.testing.assert_allclose(result_delta_t, expected_delta_t, rtol=1e-5) diff --git a/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump b/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump new file mode 100644 index 0000000000..14ed8ecddd --- /dev/null +++ b/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump @@ -0,0 +1,264 @@ +ITEM: TIMESTEP +1 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0355600153744795e+01 2.0355600153744795e+01 +-2.0355600153744795e+01 2.0355600153744795e+01 +-2.0355600153744795e+01 2.0355600153744795e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.615361 0.916658 0.977605 0 0 0 +2 1 1 0 0.631398 0.899396 0.979776 0 0 0 +3 1 1 0 0.648404 0.88913 0.992135 0 0 0 +4 1 1 0 0.63267 0.875729 0.982023 0 0 0 +5 1 1 0 0.626438 0.883425 0.00280166 0 0 1 +6 1 1 0 0.637453 0.886813 0.024039 0 0 1 +7 1 1 0 0.652249 0.886889 0.0430888 0 0 1 +8 1 1 0 0.672732 0.883924 0.0523325 0 0 1 +9 1 1 0 0.657811 0.894604 0.0691854 0 0 1 +10 1 1 0 0.65649 0.916462 0.0804671 0 0 1 +11 1 1 0 0.665957 0.901445 0.0962088 0 0 1 +12 1 1 0 0.68522 0.907309 0.106795 0 0 1 +13 1 1 0 0.673061 0.895647 0.12283 0 0 1 +14 1 1 0 0.677892 0.879177 0.106639 0 0 1 +15 1 1 0 0.658043 0.879484 0.0932177 0 0 1 +ITEM: TIMESTEP +2 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0355603615290111e+01 2.0355603615290111e+01 +-2.0355603615290111e+01 2.0355603615290111e+01 +-2.0355603615290111e+01 2.0355603615290111e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.615491 0.91664 0.977656 0 0 0 +2 1 1 0 0.631369 0.899354 0.979803 0 0 0 +3 1 1 0 0.648464 0.889402 0.991954 0 0 0 +4 1 1 0 0.632719 0.875717 0.982054 0 0 0 +5 1 1 0 0.62648 0.883378 0.0027113 0 0 1 +6 1 1 0 0.637437 0.886657 0.024367 0 0 1 +7 1 1 0 0.652365 0.886662 0.0430756 0 0 1 +8 1 1 0 0.672732 0.88379 0.0520738 0 0 1 +9 1 1 0 0.657792 0.894523 0.0692184 0 0 1 +10 1 1 0 0.65657 0.916546 0.08031 0 0 1 +11 1 1 0 0.665797 0.90159 0.0963197 0 0 1 +12 1 1 0 0.685232 0.907541 0.106812 0 0 1 +13 1 1 0 0.672891 0.895405 0.122929 0 0 1 +14 1 1 0 0.677881 0.879209 0.106594 0 0 1 +15 1 1 0 0.657968 0.879496 0.093186 0 0 1 +ITEM: TIMESTEP +4 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0355610545665090e+01 2.0355610545665090e+01 +-2.0355610545665090e+01 2.0355610545665090e+01 +-2.0355610545665090e+01 2.0355610545665090e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.615719 0.916574 0.977758 0 0 0 +2 1 1 0 0.631259 0.899327 0.979874 0 0 0 +3 1 1 0 0.648652 0.889988 0.991619 0 0 0 +4 1 1 0 0.63284 0.875581 0.982058 0 0 0 +5 1 1 0 0.626644 0.883295 0.00265416 0 0 1 +6 1 1 0 0.637401 0.886324 0.0249678 0 0 1 +7 1 1 0 0.652469 0.886219 0.0429842 0 0 1 +8 1 1 0 0.672776 0.883545 0.0517394 0 0 1 +9 1 1 0 0.657776 0.894369 0.0692668 0 0 1 +10 1 1 0 0.656727 0.916605 0.0799941 0 0 1 +11 1 1 0 0.665477 0.901964 0.0965097 0 0 1 +12 1 1 0 0.685271 0.908083 0.106952 0 0 1 +13 1 1 0 0.672591 0.894954 0.123069 0 0 1 +14 1 1 0 0.677802 0.879268 0.106524 0 0 1 +15 1 1 0 0.657972 0.879341 0.0930271 0 0 1 +ITEM: TIMESTEP +8 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0355624425159920e+01 2.0355624425159920e+01 +-2.0355624425159920e+01 2.0355624425159920e+01 +-2.0355624425159920e+01 2.0355624425159920e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.616006 0.916443 0.977892 0 0 0 +2 1 1 0 0.630818 0.899376 0.980077 0 0 0 +3 1 1 0 0.649256 0.891177 0.991051 0 0 0 +4 1 1 0 0.633264 0.874995 0.981907 0 0 0 +5 1 1 0 0.627256 0.883173 0.00305087 0 0 1 +6 1 1 0 0.637186 0.885571 0.0257625 0 0 1 +7 1 1 0 0.652234 0.88538 0.0426589 0 0 1 +8 1 1 0 0.673077 0.883186 0.0518193 0 0 1 +9 1 1 0 0.657855 0.894068 0.0692517 0 0 1 +10 1 1 0 0.657053 0.916208 0.0794189 0 0 1 +11 1 1 0 0.66495 0.90296 0.0968392 0 0 1 +12 1 1 0 0.685278 0.909178 0.107584 0 0 1 +13 1 1 0 0.672306 0.894367 0.122982 0 0 1 +14 1 1 0 0.677482 0.879313 0.106397 0 0 1 +15 1 1 0 0.658316 0.878697 0.0925012 0 0 1 +ITEM: TIMESTEP +16 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0355652203773612e+01 2.0355652203773612e+01 +-2.0355652203773612e+01 2.0355652203773612e+01 +-2.0355652203773612e+01 2.0355652203773612e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.615575 0.916953 0.977501 0 0 0 +2 1 1 0 0.629751 0.898727 0.981024 0 0 0 +3 1 1 0 0.650483 0.892872 0.98997 0 0 0 +4 1 1 0 0.635076 0.873978 0.98216 0 0 0 +5 1 1 0 0.629168 0.882789 0.0043001 0 0 1 +6 1 1 0 0.6358 0.883994 0.025552 0 0 1 +7 1 1 0 0.652013 0.88383 0.0426954 0 0 1 +8 1 1 0 0.673463 0.883026 0.0536994 0 0 1 +9 1 1 0 0.658396 0.893137 0.0686492 0 0 1 +10 1 1 0 0.657585 0.914034 0.0782405 0 0 1 +11 1 1 0 0.664795 0.904917 0.0981176 0 0 1 +12 1 1 0 0.684787 0.909811 0.108785 0 0 1 +13 1 1 0 0.672999 0.895003 0.12184 0 0 1 +14 1 1 0 0.67687 0.878746 0.105873 0 0 1 +15 1 1 0 0.658398 0.878321 0.0914959 0 0 1 +ITEM: TIMESTEP +32 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0355707886159603e+01 2.0355707886159603e+01 +-2.0355707886159603e+01 2.0355707886159603e+01 +-2.0355707886159603e+01 2.0355707886159603e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.613435 0.916559 0.976467 0 0 0 +2 1 1 0 0.627485 0.899059 0.984065 0 0 0 +3 1 1 0 0.650294 0.893892 0.988746 0 0 0 +4 1 1 0 0.640612 0.873145 0.983177 0 0 0 +5 1 1 0 0.631807 0.882126 0.00390726 0 0 1 +6 1 1 0 0.637315 0.885369 0.0274023 0 0 1 +7 1 1 0 0.653768 0.883342 0.0439789 0 0 1 +8 1 1 0 0.675085 0.881167 0.0545631 0 0 1 +9 1 1 0 0.656816 0.889778 0.0684146 0 0 1 +10 1 1 0 0.65784 0.911406 0.0779864 0 0 1 +11 1 1 0 0.66368 0.906193 0.0998673 0 0 1 +12 1 1 0 0.687786 0.909147 0.105335 0 0 1 +13 1 1 0 0.673776 0.8953 0.1212 0 0 1 +14 1 1 0 0.675965 0.87761 0.105024 0 0 1 +15 1 1 0 0.656485 0.880392 0.0909747 0 0 1 +ITEM: TIMESTEP +64 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0355819396722975e+01 2.0355819396722975e+01 +-2.0355819396722975e+01 2.0355819396722975e+01 +-2.0355819396722975e+01 2.0355819396722975e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.612397 0.915364 0.975077 0 0 0 +2 1 1 0 0.627017 0.899021 0.984177 0 0 0 +3 1 1 0 0.65009 0.894923 0.988037 0 0 0 +4 1 1 0 0.640029 0.873573 0.982576 0 0 0 +5 1 1 0 0.631138 0.882347 0.00388604 0 0 1 +6 1 1 0 0.642827 0.888427 0.0240709 0 0 1 +7 1 1 0 0.657126 0.889982 0.0429142 0 0 1 +8 1 1 0 0.677502 0.88062 0.0516138 0 0 1 +9 1 1 0 0.665198 0.890914 0.070222 0 0 1 +10 1 1 0 0.653378 0.909947 0.0800473 0 0 1 +11 1 1 0 0.664993 0.904892 0.100965 0 0 1 +12 1 1 0 0.687459 0.903302 0.102878 0 0 1 +13 1 1 0 0.678095 0.89323 0.121566 0 0 1 +14 1 1 0 0.678102 0.88105 0.10132 0 0 1 +15 1 1 0 0.655175 0.879363 0.094859 0 0 1 +ITEM: TIMESTEP +128 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0356045145307441e+01 2.0356045145307441e+01 +-2.0356045145307441e+01 2.0356045145307441e+01 +-2.0356045145307441e+01 2.0356045145307441e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.615243 0.919081 0.977376 0 0 0 +2 1 1 0 0.632321 0.905551 0.986006 0 0 0 +3 1 1 0 0.654431 0.894739 0.983651 0 0 0 +4 1 1 0 0.638793 0.87805 0.980686 0 0 0 +5 1 1 0 0.636785 0.885242 0.00369442 0 0 1 +6 1 1 0 0.649105 0.893731 0.0217439 0 0 1 +7 1 1 0 0.653512 0.891718 0.0464078 0 0 1 +8 1 1 0 0.675349 0.891617 0.0534082 0 0 1 +9 1 1 0 0.661515 0.894532 0.0724292 0 0 1 +10 1 1 0 0.652331 0.912173 0.084505 0 0 1 +11 1 1 0 0.66666 0.905874 0.102395 0 0 1 +12 1 1 0 0.689428 0.90439 0.10817 0 0 1 +13 1 1 0 0.675708 0.894913 0.123856 0 0 1 +14 1 1 0 0.678148 0.880247 0.105302 0 0 1 +15 1 1 0 0.657725 0.884598 0.0939046 0 0 1 +ITEM: TIMESTEP +256 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0356514719385785e+01 2.0356514719385785e+01 +-2.0356514719385785e+01 2.0356514719385785e+01 +-2.0356514719385785e+01 2.0356514719385785e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.619466 0.922681 0.970428 0 0 0 +2 1 1 0 0.631589 0.909615 0.984267 0 0 0 +3 1 1 0 0.65253 0.897326 0.988031 0 0 0 +4 1 1 0 0.642706 0.876486 0.988435 0 0 0 +5 1 1 0 0.636007 0.880319 0.0097077 0 0 1 +6 1 1 0 0.656444 0.894027 0.0127605 0 0 1 +7 1 1 0 0.657297 0.890755 0.0376228 0 0 1 +8 1 1 0 0.669476 0.889982 0.0567176 0 0 1 +9 1 1 0 0.647482 0.888321 0.0651679 0 0 1 +10 1 1 0 0.655117 0.907372 0.0795585 0 0 1 +11 1 1 0 0.672847 0.903298 0.0939032 0 0 1 +12 1 1 0 0.689449 0.902073 0.111466 0 0 1 +13 1 1 0 0.667796 0.89178 0.117445 0 0 1 +14 1 1 0 0.679951 0.877666 0.102567 0 0 1 +15 1 1 0 0.657944 0.880017 0.0954321 0 0 1 +ITEM: TIMESTEP +512 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0357512117776135e+01 2.0357512117776135e+01 +-2.0357512117776135e+01 2.0357512117776135e+01 +-2.0357512117776135e+01 2.0357512117776135e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.619846 0.917655 0.993467 0 0 0 +2 1 1 0 0.61705 0.896707 0.980912 0 0 0 +3 1 1 0 0.638851 0.889076 0.986676 0 0 0 +4 1 1 0 0.64121 0.8686 0.995096 0 0 0 +5 1 1 0 0.636671 0.883339 0.0126369 0 0 1 +6 1 1 0 0.659342 0.888701 0.00398138 0 0 1 +7 1 1 0 0.656349 0.888655 0.02843 0 0 1 +8 1 1 0 0.666885 0.888935 0.0487139 0 0 1 +9 1 1 0 0.646898 0.878177 0.0614737 0 0 1 +10 1 1 0 0.655031 0.898687 0.0709038 0 0 1 +11 1 1 0 0.665319 0.901307 0.0916725 0 0 1 +12 1 1 0 0.680209 0.904584 0.110239 0 0 1 +13 1 1 0 0.666398 0.884577 0.111957 0 0 1 +14 1 1 0 0.670707 0.868407 0.0947354 0 0 1 +15 1 1 0 0.652102 0.879773 0.0878579 0 0 1 +ITEM: TIMESTEP +1024 +ITEM: NUMBER OF ATOMS +15 +ITEM: BOX BOUNDS pp pp pp +-2.0359510373749348e+01 2.0359510373749348e+01 +-2.0359510373749348e+01 2.0359510373749348e+01 +-2.0359510373749348e+01 2.0359510373749348e+01 +ITEM: ATOMS id mol type q xs ys zs ix iy iz +1 1 1 0 0.628446 0.918265 0.989162 0 0 0 +2 1 1 0 0.614481 0.90596 0.973887 0 0 0 +3 1 1 0 0.623009 0.883136 0.973127 0 0 0 +4 1 1 0 0.62809 0.869983 0.991524 0 0 0 +5 1 1 0 0.638659 0.880527 0.00929481 0 0 1 +6 1 1 0 0.660935 0.883049 0.0188596 0 0 1 +7 1 1 0 0.662719 0.862462 0.0298895 0 0 1 +8 1 1 0 0.664646 0.86312 0.0535608 0 0 1 +9 1 1 0 0.652297 0.856703 0.0729134 0 0 1 +10 1 1 0 0.65923 0.877509 0.0843681 0 0 1 +11 1 1 0 0.679945 0.883899 0.0917732 0 0 1 +12 1 1 0 0.664801 0.89156 0.109159 0 0 1 +13 1 1 0 0.675896 0.873331 0.119055 0 0 1 +14 1 1 0 0.660676 0.86256 0.105118 0 0 1 +15 1 1 0 0.647792 0.877426 0.119059 0 0 1 diff --git a/testsuite/MDAnalysisTests/datafiles.py b/testsuite/MDAnalysisTests/datafiles.py index 879bce4891..8181f12273 100644 --- a/testsuite/MDAnalysisTests/datafiles.py +++ b/testsuite/MDAnalysisTests/datafiles.py @@ -906,6 +906,7 @@ SURFACE_PDB = (_data_ref / "surface.pdb.bz2").as_posix() SURFACE_TRR = (_data_ref / "surface.trr").as_posix() +LAMMPSDUMP_non_linear = (_data_ref / "custom_non_linear/test_non_linear.dump").as_posix() # DSSP testing: from https://github.com/ShintaroMinami/PyDSSP DSSP = (_data_ref / "dssp").as_posix() From 00fc30936decefe19fe5502c4ad10f0d88047ba9 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Tue, 22 Jul 2025 13:24:49 -0400 Subject: [PATCH 07/26] added LAMMPSDUMP_non_linear to __all__ --- testsuite/MDAnalysisTests/datafiles.py | 1 + 1 file changed, 1 insertion(+) diff --git a/testsuite/MDAnalysisTests/datafiles.py b/testsuite/MDAnalysisTests/datafiles.py index 8181f12273..e32807058f 100644 --- a/testsuite/MDAnalysisTests/datafiles.py +++ b/testsuite/MDAnalysisTests/datafiles.py @@ -389,6 +389,7 @@ "SURFACE_PDB", # 111 FCC lattice topology for NSGrid bug #2345 "SURFACE_TRR", # full precision coordinates for NSGrid bug #2345 "DSSP", # DSSP test suite + "LAMMPSDUMP_non_linear" ] from importlib import resources From c90f52e59b6db649524998146c96f5d89a266947 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Tue, 22 Jul 2025 15:51:59 -0400 Subject: [PATCH 08/26] ran black 24.10.0 --- benchmarks/benchmarks/analysis/rms.py | 4 +- package/MDAnalysis/__init__.py | 8 +- package/MDAnalysis/analysis/align.py | 455 ++++++---- .../MDAnalysis/analysis/atomicdistances.py | 15 +- package/MDAnalysis/analysis/base.py | 51 +- package/MDAnalysis/analysis/bat.py | 19 +- package/MDAnalysis/analysis/contacts.py | 8 +- package/MDAnalysis/analysis/density.py | 29 +- package/MDAnalysis/analysis/diffusionmap.py | 70 +- package/MDAnalysis/analysis/dihedrals.py | 46 +- package/MDAnalysis/analysis/distances.py | 4 +- package/MDAnalysis/analysis/dssp/dssp.py | 7 +- .../MDAnalysis/analysis/dssp/pydssp_numpy.py | 13 +- .../MDAnalysis/analysis/encore/bootstrap.py | 4 +- .../encore/clustering/ClusterCollection.py | 11 +- .../encore/clustering/ClusteringMethod.py | 20 +- .../analysis/encore/clustering/cluster.py | 21 +- .../analysis/encore/confdistmatrix.py | 54 +- .../MDAnalysis/analysis/encore/covariance.py | 16 +- .../DimensionalityReductionMethod.py | 28 +- .../reduce_dimensionality.py | 16 +- .../MDAnalysis/analysis/encore/similarity.py | 53 +- package/MDAnalysis/analysis/encore/utils.py | 12 +- package/MDAnalysis/analysis/gnm.py | 16 +- .../analysis/hbonds/hbond_autocorrel.py | 6 +- package/MDAnalysis/analysis/helix_analysis.py | 20 +- .../analysis/hydrogenbonds/hbond_analysis.py | 302 +++---- .../hydrogenbonds/hbond_autocorrel.py | 34 +- .../hydrogenbonds/wbridge_analysis.py | 143 +--- package/MDAnalysis/analysis/leaflet.py | 5 +- package/MDAnalysis/analysis/legacy/x3dna.py | 46 +- package/MDAnalysis/analysis/lineardensity.py | 43 +- package/MDAnalysis/analysis/nucleicacids.py | 20 +- package/MDAnalysis/analysis/pca.py | 16 +- package/MDAnalysis/analysis/polymer.py | 7 +- package/MDAnalysis/analysis/rdf.py | 10 +- package/MDAnalysis/analysis/results.py | 12 +- package/MDAnalysis/analysis/rms.py | 73 +- package/MDAnalysis/auxiliary/EDR.py | 10 +- package/MDAnalysis/auxiliary/base.py | 37 +- package/MDAnalysis/converters/OpenMM.py | 12 +- package/MDAnalysis/converters/OpenMMParser.py | 4 +- package/MDAnalysis/converters/ParmEd.py | 33 +- package/MDAnalysis/converters/ParmEdParser.py | 4 +- .../MDAnalysis/converters/RDKitInferring.py | 33 +- package/MDAnalysis/converters/RDKitParser.py | 8 +- package/MDAnalysis/coordinates/CRD.py | 16 +- package/MDAnalysis/coordinates/DCD.py | 127 +-- package/MDAnalysis/coordinates/DLPoly.py | 41 +- package/MDAnalysis/coordinates/DMS.py | 8 +- package/MDAnalysis/coordinates/FHIAIMS.py | 8 +- package/MDAnalysis/coordinates/GMS.py | 64 +- package/MDAnalysis/coordinates/GRO.py | 48 +- package/MDAnalysis/coordinates/H5MD.py | 777 ++++++++++-------- package/MDAnalysis/coordinates/LAMMPS.py | 64 +- package/MDAnalysis/coordinates/MMTF.py | 4 +- package/MDAnalysis/coordinates/MOL2.py | 74 +- package/MDAnalysis/coordinates/NAMDBIN.py | 4 +- package/MDAnalysis/coordinates/PDB.py | 502 ++++++----- package/MDAnalysis/coordinates/PDBQT.py | 16 +- package/MDAnalysis/coordinates/PQR.py | 12 +- package/MDAnalysis/coordinates/TNG.py | 42 +- package/MDAnalysis/coordinates/TRC.py | 41 +- package/MDAnalysis/coordinates/TRJ.py | 453 +++++----- package/MDAnalysis/coordinates/TRR.py | 28 +- package/MDAnalysis/coordinates/TRZ.py | 422 +++++----- package/MDAnalysis/coordinates/TXYZ.py | 15 +- package/MDAnalysis/coordinates/XDR.py | 4 +- package/MDAnalysis/coordinates/XTC.py | 32 +- package/MDAnalysis/coordinates/XYZ.py | 76 +- package/MDAnalysis/coordinates/__init__.py | 2 +- package/MDAnalysis/coordinates/base.py | 266 +++--- package/MDAnalysis/coordinates/chain.py | 157 ++-- package/MDAnalysis/coordinates/memory.py | 154 ++-- package/MDAnalysis/core/_get_readers.py | 8 +- package/MDAnalysis/core/groups.py | 132 +-- package/MDAnalysis/core/selection.py | 626 +++++++++----- package/MDAnalysis/core/topology.py | 5 +- package/MDAnalysis/core/topologyattrs.py | 93 +-- package/MDAnalysis/core/topologyobjects.py | 15 +- package/MDAnalysis/core/universe.py | 572 +++++++------ package/MDAnalysis/due.py | 4 +- package/MDAnalysis/guesser/base.py | 7 +- package/MDAnalysis/guesser/default_guesser.py | 21 +- package/MDAnalysis/lib/NeighborSearch.py | 4 +- package/MDAnalysis/lib/_distopia.py | 4 +- package/MDAnalysis/lib/distances.py | 28 +- package/MDAnalysis/lib/mdamath.py | 12 +- package/MDAnalysis/lib/picklable_file_io.py | 12 +- package/MDAnalysis/lib/pkdtree.py | 51 +- package/MDAnalysis/lib/transformations.py | 28 +- package/MDAnalysis/lib/util.py | 76 +- package/MDAnalysis/selections/base.py | 12 +- package/MDAnalysis/selections/charmm.py | 10 +- package/MDAnalysis/selections/pymol.py | 4 +- package/MDAnalysis/topology/CRDParser.py | 16 +- package/MDAnalysis/topology/DMSParser.py | 4 +- package/MDAnalysis/topology/GMSParser.py | 4 +- package/MDAnalysis/topology/GSDParser.py | 4 +- package/MDAnalysis/topology/ITPParser.py | 32 +- package/MDAnalysis/topology/LAMMPSParser.py | 28 +- package/MDAnalysis/topology/MMTFParser.py | 18 +- package/MDAnalysis/topology/MOL2Parser.py | 8 +- package/MDAnalysis/topology/PDBParser.py | 164 ++-- package/MDAnalysis/topology/PSFParser.py | 10 +- package/MDAnalysis/topology/TOPParser.py | 20 +- package/MDAnalysis/topology/TPRParser.py | 4 +- package/MDAnalysis/topology/__init__.py | 22 +- package/MDAnalysis/topology/base.py | 19 +- package/MDAnalysis/topology/guessers.py | 8 +- package/MDAnalysis/topology/tpr/obj.py | 4 +- package/MDAnalysis/topology/tpr/utils.py | 176 ++-- .../transformations/boxdimensions.py | 4 +- package/MDAnalysis/transformations/fit.py | 36 +- package/MDAnalysis/transformations/nojump.py | 11 +- .../transformations/positionaveraging.py | 4 +- package/MDAnalysis/transformations/rotate.py | 20 +- .../MDAnalysis/transformations/translate.py | 20 +- package/MDAnalysis/transformations/wrap.py | 12 +- package/MDAnalysis/units.py | 6 +- .../MDAnalysis/visualization/streamlines.py | 42 +- .../visualization/streamlines_3D.py | 91 +- package/doc/sphinx/source/conf.py | 4 +- package/setup.py | 27 +- .../MDAnalysisTests/analysis/test_align.py | 91 +- .../analysis/test_atomicdistances.py | 8 +- .../MDAnalysisTests/analysis/test_base.py | 44 +- .../MDAnalysisTests/analysis/test_bat.py | 14 +- .../MDAnalysisTests/analysis/test_contacts.py | 36 +- .../MDAnalysisTests/analysis/test_density.py | 32 +- .../analysis/test_dielectric.py | 4 +- .../analysis/test_diffusionmap.py | 16 +- .../analysis/test_dihedrals.py | 26 +- .../analysis/test_distances.py | 28 +- .../MDAnalysisTests/analysis/test_dssp.py | 24 +- .../MDAnalysisTests/analysis/test_encore.py | 142 ++-- .../MDAnalysisTests/analysis/test_gnm.py | 4 +- .../analysis/test_helix_analysis.py | 36 +- .../analysis/test_hydrogenbondautocorrel.py | 8 +- .../test_hydrogenbondautocorrel_deprecated.py | 8 +- .../analysis/test_hydrogenbonds_analysis.py | 68 +- .../MDAnalysisTests/analysis/test_leaflet.py | 18 +- .../analysis/test_lineardensity.py | 51 +- .../MDAnalysisTests/analysis/test_nuclinfo.py | 4 +- .../MDAnalysisTests/analysis/test_pca.py | 24 +- .../analysis/test_persistencelength.py | 4 +- .../MDAnalysisTests/analysis/test_rdf.py | 4 +- .../MDAnalysisTests/analysis/test_rdf_s.py | 8 +- .../MDAnalysisTests/analysis/test_results.py | 8 +- .../MDAnalysisTests/analysis/test_rms.py | 39 +- .../MDAnalysisTests/analysis/test_wbridge.py | 88 +- testsuite/MDAnalysisTests/auxiliary/base.py | 25 +- .../MDAnalysisTests/auxiliary/test_core.py | 16 +- .../MDAnalysisTests/auxiliary/test_edr.py | 51 +- .../MDAnalysisTests/auxiliary/test_xvg.py | 8 +- .../MDAnalysisTests/converters/test_base.py | 4 +- .../converters/test_openmm_parser.py | 8 +- .../MDAnalysisTests/converters/test_parmed.py | 19 +- .../converters/test_parmed_parser.py | 12 +- .../MDAnalysisTests/converters/test_rdkit.py | 71 +- .../converters/test_rdkit_parser.py | 21 +- testsuite/MDAnalysisTests/coordinates/base.py | 89 +- .../MDAnalysisTests/coordinates/reference.py | 12 +- .../coordinates/test_chainreader.py | 40 +- .../coordinates/test_chemfiles.py | 24 +- .../coordinates/test_copying.py | 4 +- .../MDAnalysisTests/coordinates/test_crd.py | 8 +- .../MDAnalysisTests/coordinates/test_dcd.py | 15 +- .../coordinates/test_dlpoly.py | 8 +- .../MDAnalysisTests/coordinates/test_dms.py | 7 +- .../coordinates/test_fhiaims.py | 44 +- .../MDAnalysisTests/coordinates/test_gms.py | 4 +- .../MDAnalysisTests/coordinates/test_gro.py | 16 +- .../MDAnalysisTests/coordinates/test_h5md.py | 119 +-- .../coordinates/test_lammps.py | 86 +- .../coordinates/test_memory.py | 24 +- .../MDAnalysisTests/coordinates/test_mol2.py | 12 +- .../coordinates/test_netcdf.py | 90 +- .../MDAnalysisTests/coordinates/test_pdb.py | 101 +-- .../MDAnalysisTests/coordinates/test_pdbqt.py | 4 +- .../MDAnalysisTests/coordinates/test_pqr.py | 4 +- .../coordinates/test_reader_api.py | 4 +- .../coordinates/test_timestep_api.py | 20 +- .../MDAnalysisTests/coordinates/test_tng.py | 52 +- .../MDAnalysisTests/coordinates/test_trc.py | 38 +- .../MDAnalysisTests/coordinates/test_trj.py | 15 +- .../MDAnalysisTests/coordinates/test_trz.py | 16 +- .../MDAnalysisTests/coordinates/test_txyz.py | 12 +- .../coordinates/test_writer_api.py | 12 +- .../coordinates/test_writer_registration.py | 4 +- .../MDAnalysisTests/coordinates/test_xdr.py | 64 +- .../MDAnalysisTests/core/test_accessors.py | 9 +- .../MDAnalysisTests/core/test_accumulate.py | 20 +- testsuite/MDAnalysisTests/core/test_atom.py | 4 +- .../MDAnalysisTests/core/test_atomgroup.py | 131 +-- .../core/test_atomselections.py | 77 +- .../core/test_group_traj_access.py | 46 +- testsuite/MDAnalysisTests/core/test_groups.py | 62 +- .../MDAnalysisTests/core/test_residuegroup.py | 11 +- .../MDAnalysisTests/core/test_topology.py | 4 +- .../core/test_topologyattrs.py | 20 +- .../core/test_topologyobjects.py | 16 +- .../MDAnalysisTests/core/test_universe.py | 133 +-- testsuite/MDAnalysisTests/core/test_unwrap.py | 32 +- .../core/test_updating_atomgroup.py | 24 +- testsuite/MDAnalysisTests/core/test_wrap.py | 36 +- testsuite/MDAnalysisTests/core/util.py | 4 +- testsuite/MDAnalysisTests/datafiles.py | 114 +-- testsuite/MDAnalysisTests/dummy.py | 8 +- .../MDAnalysisTests/formats/test_libdcd.py | 11 +- .../MDAnalysisTests/formats/test_libmdaxdr.py | 8 +- .../MDAnalysisTests/guesser/test_base.py | 19 +- .../guesser/test_default_guesser.py | 29 +- testsuite/MDAnalysisTests/lib/test_cutil.py | 4 +- .../MDAnalysisTests/lib/test_distances.py | 176 ++-- .../lib/test_neighborsearch.py | 4 +- testsuite/MDAnalysisTests/lib/test_nsgrid.py | 34 +- testsuite/MDAnalysisTests/lib/test_util.py | 138 +--- testsuite/MDAnalysisTests/test_api.py | 3 +- testsuite/MDAnalysisTests/topology/base.py | 12 +- .../MDAnalysisTests/topology/test_fhiaims.py | 4 +- .../MDAnalysisTests/topology/test_gms.py | 4 +- .../MDAnalysisTests/topology/test_guessers.py | 4 +- .../MDAnalysisTests/topology/test_itp.py | 20 +- .../topology/test_lammpsdata.py | 4 +- .../MDAnalysisTests/topology/test_minimal.py | 4 +- .../MDAnalysisTests/topology/test_mol2.py | 8 +- .../MDAnalysisTests/topology/test_pdb.py | 5 +- .../MDAnalysisTests/topology/test_pqr.py | 4 +- .../MDAnalysisTests/topology/test_top.py | 23 +- .../topology/test_topology_base.py | 4 +- .../topology/test_tprparser.py | 8 +- .../MDAnalysisTests/topology/test_txyz.py | 4 +- .../transformations/test_base.py | 4 +- .../transformations/test_boxdimensions.py | 16 +- .../transformations/test_fit.py | 4 +- .../transformations/test_nojump.py | 16 +- .../transformations/test_positionaveraging.py | 8 +- .../transformations/test_rotate.py | 22 +- .../transformations/test_translate.py | 12 +- .../transformations/test_wrap.py | 8 +- testsuite/MDAnalysisTests/util.py | 7 +- .../MDAnalysisTests/utils/test_authors.py | 4 +- .../MDAnalysisTests/utils/test_duecredit.py | 5 +- .../MDAnalysisTests/utils/test_failure.py | 4 +- .../MDAnalysisTests/utils/test_imports.py | 4 +- testsuite/MDAnalysisTests/utils/test_meta.py | 4 +- .../MDAnalysisTests/utils/test_modelling.py | 51 +- .../MDAnalysisTests/utils/test_pickleio.py | 16 +- .../MDAnalysisTests/utils/test_qcprot.py | 4 +- .../MDAnalysisTests/utils/test_selections.py | 8 +- .../MDAnalysisTests/utils/test_streamio.py | 12 +- .../utils/test_transformations.py | 8 +- testsuite/MDAnalysisTests/utils/test_units.py | 4 +- .../visualization/test_streamlines.py | 8 +- 255 files changed, 4798 insertions(+), 6593 deletions(-) diff --git a/benchmarks/benchmarks/analysis/rms.py b/benchmarks/benchmarks/analysis/rms.py index 80afc15f18..2f5b91f399 100644 --- a/benchmarks/benchmarks/analysis/rms.py +++ b/benchmarks/benchmarks/analysis/rms.py @@ -28,7 +28,9 @@ def setup(self, num_atoms, use_weights, center, superposition): self.u.trajectory[-1] self.B = self.u.atoms.positions.copy()[:num_atoms] self.atoms = self.u.atoms[:num_atoms] - self.weights = self.atoms.masses/np.sum(self.atoms.masses) if use_weights else None + self.weights = ( + self.atoms.masses / np.sum(self.atoms.masses) if use_weights else None + ) def time_rmsd(self, num_atoms, weights, center, superposition): """Benchmark rmsd function using a setup similar to diff --git a/package/MDAnalysis/__init__.py b/package/MDAnalysis/__init__.py index 6843c3738a..9cb8ca9764 100644 --- a/package/MDAnalysis/__init__.py +++ b/package/MDAnalysis/__init__.py @@ -179,9 +179,7 @@ _CONVERTERS: Dict = {} # Registry of TopologyAttributes _TOPOLOGY_ATTRS: Dict = {} # {attrname: cls} -_TOPOLOGY_TRANSPLANTS: Dict = ( - {} -) # {name: [attrname, method, transplant class]} +_TOPOLOGY_TRANSPLANTS: Dict = {} # {name: [attrname, method, transplant class]} _TOPOLOGY_ATTRNAMES: Dict = {} # {lower case name w/o _ : name} _GUESSERS: Dict = {} @@ -204,9 +202,7 @@ del logging # only MDAnalysis DeprecationWarnings are loud by default -warnings.filterwarnings( - action="once", category=DeprecationWarning, module="MDAnalysis" -) +warnings.filterwarnings(action="once", category=DeprecationWarning, module="MDAnalysis") from . import units diff --git a/package/MDAnalysis/analysis/align.py b/package/MDAnalysis/analysis/align.py index acf87dbf65..e7b6e482eb 100644 --- a/package/MDAnalysis/analysis/align.py +++ b/package/MDAnalysis/analysis/align.py @@ -212,13 +212,13 @@ import MDAnalysis.analysis.rms as rms from MDAnalysis.coordinates.memory import MemoryReader from MDAnalysis.lib.util import get_weights -from MDAnalysis.lib.util import deprecate # remove 3.0 +from MDAnalysis.lib.util import deprecate # remove 3.0 from MDAnalysis.lib.log import ProgressBar from ..due import due, Doi from .base import AnalysisBase -logger = logging.getLogger('MDAnalysis.analysis.align') +logger = logging.getLogger("MDAnalysis.analysis.align") def rotation_matrix(a, b, weights=None): @@ -280,7 +280,6 @@ def rotation_matrix(a, b, weights=None): AlignTraj: Fit a whole trajectory. """ - a = np.asarray(a, dtype=np.float64) b = np.asarray(b, dtype=np.float64) @@ -307,8 +306,9 @@ def rotation_matrix(a, b, weights=None): return rot.reshape(3, 3), rmsd -def _fit_to(mobile_coordinates, ref_coordinates, mobile_atoms, - mobile_com, ref_com, weights=None): +def _fit_to( + mobile_coordinates, ref_coordinates, mobile_atoms, mobile_com, ref_com, weights=None +): r"""Perform an rmsd-fitting to determine rotation matrix and align atoms Parameters @@ -356,8 +356,7 @@ def _fit_to(mobile_coordinates, ref_coordinates, mobile_atoms, where :math:`\bar{X}` is the center. """ - R, min_rmsd = rotation_matrix(mobile_coordinates, ref_coordinates, - weights=weights) + R, min_rmsd = rotation_matrix(mobile_coordinates, ref_coordinates, weights=weights) mobile_atoms.translate(-mobile_com) mobile_atoms.rotate(R) @@ -366,9 +365,16 @@ def _fit_to(mobile_coordinates, ref_coordinates, mobile_atoms, return mobile_atoms, min_rmsd -def alignto(mobile, reference, select=None, weights=None, - subselection=None, tol_mass=0.1, strict=False, - match_atoms=True): +def alignto( + mobile, + reference, + select=None, + weights=None, + subselection=None, + tol_mass=0.1, + strict=False, + match_atoms=True, +): """Perform a spatial superposition by minimizing the RMSD. Spatially align the group of atoms `mobile` to `reference` by @@ -494,7 +500,7 @@ def alignto(mobile, reference, select=None, weights=None, .. versionchanged:: 0.17.0 Deprecated keyword `mass_weighted` was removed. """ - if select in ('all', None): + if select in ("all", None): # keep the EXACT order in the input AtomGroups; select_atoms('all') # orders them by index, which can lead to wrong results if the user # has crafted mobile and reference to match atom by atom @@ -502,14 +508,16 @@ def alignto(mobile, reference, select=None, weights=None, ref_atoms = reference.atoms else: select = rms.process_selection(select) - mobile_atoms = mobile.select_atoms(*select['mobile']) - ref_atoms = reference.select_atoms(*select['reference']) - - - ref_atoms, mobile_atoms = get_matching_atoms(ref_atoms, mobile_atoms, - tol_mass=tol_mass, - strict=strict, - match_atoms=match_atoms) + mobile_atoms = mobile.select_atoms(*select["mobile"]) + ref_atoms = reference.select_atoms(*select["reference"]) + + ref_atoms, mobile_atoms = get_matching_atoms( + ref_atoms, + mobile_atoms, + tol_mass=tol_mass, + strict=strict, + match_atoms=match_atoms, + ) weights = get_weights(ref_atoms, weights) @@ -532,26 +540,38 @@ def alignto(mobile, reference, select=None, weights=None, # treat subselection as AtomGroup mobile_atoms = subselection.atoms except AttributeError: - err = ("subselection must be a selection string, an" - " AtomGroup or Universe or None") + err = ( + "subselection must be a selection string, an" + " AtomGroup or Universe or None" + ) raise TypeError(err) from None - # _fit_to DOES subtract center of mass, will provide proper min_rmsd - mobile_atoms, new_rmsd = _fit_to(mobile_coordinates, ref_coordinates, - mobile_atoms, mobile_com, ref_com, - weights=weights) + mobile_atoms, new_rmsd = _fit_to( + mobile_coordinates, + ref_coordinates, + mobile_atoms, + mobile_com, + ref_com, + weights=weights, + ) return old_rmsd, new_rmsd @due.dcite( - Doi("10.1021/acs.jpcb.7b11988"), - description="Iterative Calculation of Opimal Reference", - path="MDAnalysis.analysis.align.iterative_average" + Doi("10.1021/acs.jpcb.7b11988"), + description="Iterative Calculation of Opimal Reference", + path="MDAnalysis.analysis.align.iterative_average", ) def iterative_average( - mobile, reference=None, select='all', weights=None, niter=100, - eps=1e-6, verbose=False, **kwargs + mobile, + reference=None, + select="all", + weights=None, + niter=100, + eps=1e-6, + verbose=False, + **kwargs, ): """Iteratively calculate an optimal reference that is also the average structure after an RMSD alignment. @@ -618,8 +638,8 @@ def iterative_average( reference = mobile select = rms.process_selection(select) - ref = mda.Merge(reference.select_atoms(*select['reference'])) - sel_mobile = select['mobile'][0] + ref = mda.Merge(reference.select_atoms(*select["reference"])) + sel_mobile = select["mobile"][0] weights = get_weights(ref.atoms, weights) @@ -630,13 +650,15 @@ def iterative_average( break avg_struc = AverageStructure( - mobile, reference=ref, select={ - 'mobile': sel_mobile, 'reference': 'all' - }, - weights=weights, **kwargs + mobile, + reference=ref, + select={"mobile": sel_mobile, "reference": "all"}, + weights=weights, + **kwargs, ).run() - drmsd = rms.rmsd(ref.atoms.positions, avg_struc.results.positions, - weights=weights) + drmsd = rms.rmsd( + ref.atoms.positions, avg_struc.results.positions, weights=weights + ) ref = avg_struc.results.universe if verbose: @@ -678,11 +700,22 @@ class AlignTraj(AnalysisBase): """ - def __init__(self, mobile, reference, select='all', filename=None, - prefix='rmsfit_', weights=None, - tol_mass=0.1, match_atoms=True, strict=False, force=True, in_memory=False, - writer_kwargs=None, - **kwargs): + def __init__( + self, + mobile, + reference, + select="all", + filename=None, + prefix="rmsfit_", + weights=None, + tol_mass=0.1, + match_atoms=True, + strict=False, + force=True, + in_memory=False, + writer_kwargs=None, + **kwargs, + ): """Parameters ---------- mobile : Universe @@ -788,8 +821,8 @@ def __init__(self, mobile, reference, select='all', filename=None, """ select = rms.process_selection(select) - self.ref_atoms = reference.select_atoms(*select['reference']) - self.mobile_atoms = mobile.select_atoms(*select['mobile']) + self.ref_atoms = reference.select_atoms(*select["reference"]) + self.mobile_atoms = mobile.select_atoms(*select["mobile"]) if in_memory or isinstance(mobile.trajectory, MemoryReader): mobile.transfer_to_memory() filename = None @@ -798,13 +831,15 @@ def __init__(self, mobile, reference, select='all', filename=None, if filename is None: fn = os.path.split(mobile.trajectory.filename)[1] filename = prefix + fn - logger.info('filename of rms_align with no filename given' - ': {0}'.format(filename)) + logger.info( + "filename of rms_align with no filename given" + ": {0}".format(filename) + ) if os.path.exists(filename) and not force: raise IOError( - 'Filename already exists in path and force is not set' - ' to True') + "Filename already exists in path and force is not set" " to True" + ) # do this after setting the memory reader to have a reference to the # right reader. @@ -819,8 +854,12 @@ def __init__(self, mobile, reference, select='all', filename=None, natoms = self.mobile.n_atoms self.ref_atoms, self.mobile_atoms = get_matching_atoms( - self.ref_atoms, self.mobile_atoms, tol_mass=tol_mass, - strict=strict, match_atoms=match_atoms) + self.ref_atoms, + self.mobile_atoms, + tol_mass=tol_mass, + strict=strict, + match_atoms=match_atoms, + ) if writer_kwargs is None: writer_kwargs = {} @@ -845,11 +884,13 @@ def _single_frame(self): mobile_com = self.mobile_atoms.center(self._weights) mobile_coordinates = self.mobile_atoms.positions - mobile_com mobile_atoms, self.results.rmsd[index] = _fit_to( - mobile_coordinates, - self._ref_coordinates, - self.mobile, - mobile_com, - self._ref_com, self._weights) + mobile_coordinates, + self._ref_coordinates, + self.mobile, + mobile_com, + self._ref_com, + self._weights, + ) # write whole aligned input trajectory system self._writer.write(mobile_atoms) @@ -860,9 +901,11 @@ def _conclude(self): @property def rmsd(self): - wmsg = ("The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 and " - "will be removed in MDAnalysis 3.0.0. Please use " - "`results.rmsd` instead.") + wmsg = ( + "The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 and " + "will be removed in MDAnalysis 3.0.0. Please use " + "`results.rmsd` instead." + ) warnings.warn(wmsg, DeprecationWarning) return self.results.rmsd @@ -896,10 +939,21 @@ class AverageStructure(AnalysisBase): """ - def __init__(self, mobile, reference=None, select='all', filename=None, - weights=None, - tol_mass=0.1, match_atoms=True, strict=False, force=True, in_memory=False, - ref_frame=0, **kwargs): + def __init__( + self, + mobile, + reference=None, + select="all", + filename=None, + weights=None, + tol_mass=0.1, + match_atoms=True, + strict=False, + force=True, + in_memory=False, + ref_frame=0, + **kwargs, + ): """Parameters ---------- mobile : Universe @@ -1017,18 +1071,20 @@ def __init__(self, mobile, reference=None, select='all', filename=None, self.reference = reference if reference is not None else mobile select = rms.process_selection(select) - self.ref_atoms = self.reference.select_atoms(*select['reference']) - self.mobile_atoms = mobile.select_atoms(*select['mobile']) + self.ref_atoms = self.reference.select_atoms(*select["reference"]) + self.mobile_atoms = mobile.select_atoms(*select["mobile"]) if len(self.ref_atoms) != len(self.mobile_atoms): - err = ("Reference and trajectory atom selections do " - "not contain the same number of atoms: " - "N_ref={0:d}, N_traj={1:d}".format(self.ref_atoms.n_atoms, - self.mobile_atoms.n_atoms)) + err = ( + "Reference and trajectory atom selections do " + "not contain the same number of atoms: " + "N_ref={0:d}, N_traj={1:d}".format( + self.ref_atoms.n_atoms, self.mobile_atoms.n_atoms + ) + ) logger.exception(err) raise SelectionError(err) - logger.info("RMS calculation " - "for {0:d} atoms.".format(len(self.ref_atoms))) + logger.info("RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms))) # store reference to mobile atoms self.mobile = mobile.atoms @@ -1039,8 +1095,12 @@ def __init__(self, mobile, reference=None, select='all', filename=None, natoms = len(self.results.universe.atoms) self.ref_atoms, self.mobile_atoms = get_matching_atoms( - self.ref_atoms, self.mobile_atoms, tol_mass=tol_mass, - strict=strict, match_atoms=match_atoms) + self.ref_atoms, + self.mobile_atoms, + tol_mass=tol_mass, + strict=strict, + match_atoms=match_atoms, + ) # with self.filename == None (in_memory), the NullWriter is chosen # (which just ignores input) and so only the in_memory trajectory is @@ -1072,18 +1132,20 @@ def _prepare(self): def _single_frame(self): mobile_com = self.mobile_atoms.center(self._weights) mobile_coordinates = self.mobile_atoms.positions - mobile_com - self.results.rmsd += _fit_to(mobile_coordinates, - self._ref_coordinates, - self.mobile, - mobile_com, - self._ref_com, self._weights)[1] + self.results.rmsd += _fit_to( + mobile_coordinates, + self._ref_coordinates, + self.mobile, + mobile_com, + self._ref_com, + self._weights, + )[1] self.results.positions += self.mobile_atoms.positions def _conclude(self): self.results.positions /= self.n_frames self.results.rmsd /= self.n_frames - self.results.universe.load_new( - self.results.positions.reshape((1, -1, 3))) + self.results.universe.load_new(self.results.positions.reshape((1, -1, 3))) self._writer.write(self.results.universe.atoms) self._writer.close() if not self._verbose: @@ -1091,34 +1153,49 @@ def _conclude(self): @property def universe(self): - wmsg = ("The `universe` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.universe` instead.") + wmsg = ( + "The `universe` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.universe` instead." + ) warnings.warn(wmsg, DeprecationWarning) return self.results.universe @property def positions(self): - wmsg = ("The `positions` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.positions` instead.") + wmsg = ( + "The `positions` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.positions` instead." + ) warnings.warn(wmsg, DeprecationWarning) return self.results.positions @property def rmsd(self): - wmsg = ("The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.rmsd` instead.") + wmsg = ( + "The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.rmsd` instead." + ) warnings.warn(wmsg, DeprecationWarning) return self.results.rmsd -@deprecate(release="2.4.0", remove="3.0", - message="See the documentation under Notes on how to directly use" - "Bio.Align.PairwiseAligner with ResidueGroups.") -def sequence_alignment(mobile, reference, match_score=2, mismatch_penalty=-1, - gap_penalty=-2, gapextension_penalty=-0.1): +@deprecate( + release="2.4.0", + remove="3.0", + message="See the documentation under Notes on how to directly use" + "Bio.Align.PairwiseAligner with ResidueGroups.", +) +def sequence_alignment( + mobile, + reference, + match_score=2, + mismatch_penalty=-1, + gap_penalty=-2, + gapextension_penalty=-0.1, +): """Generate a global sequence alignment between two residue groups. The residues in `reference` and `mobile` will be globally aligned. @@ -1201,9 +1278,11 @@ def sequence_alignment(mobile, reference, match_score=2, mismatch_penalty=-1, """ if not HAS_BIOPYTHON: - errmsg = ("The `sequence_alignment` method requires an installation " - "of `Biopython`. Please install `Biopython` to use this " - "method: https://biopython.org/wiki/Download") + errmsg = ( + "The `sequence_alignment` method requires an installation " + "of `Biopython`. Please install `Biopython` to use this " + "method: https://biopython.org/wiki/Download" + ) raise ImportError(errmsg) aligner = Bio.Align.PairwiseAligner( @@ -1211,28 +1290,42 @@ def sequence_alignment(mobile, reference, match_score=2, mismatch_penalty=-1, match_score=match_score, mismatch_score=mismatch_penalty, open_gap_score=gap_penalty, - extend_gap_score=gapextension_penalty) - aln = aligner.align(reference.residues.sequence(format="Seq"), - mobile.residues.sequence(format="Seq")) + extend_gap_score=gapextension_penalty, + ) + aln = aligner.align( + reference.residues.sequence(format="Seq"), + mobile.residues.sequence(format="Seq"), + ) # choose top alignment with highest score topalignment = aln[0] # reconstruct the results tuple that used to be of type Bio.pairwise2.Alignment AlignmentTuple = collections.namedtuple( - "Alignment", - ["seqA", "seqB", "score", "start", "end"]) + "Alignment", ["seqA", "seqB", "score", "start", "end"] + ) # start/stop are not particularly meaningful and there's no obvious way to # get the old pairwise2 start/stop from the new PairwiseAligner output. - return AlignmentTuple(topalignment[0], topalignment[1], - topalignment.score, - 0, max(reference.n_residues, mobile.n_residues)) - + return AlignmentTuple( + topalignment[0], + topalignment[1], + topalignment.score, + 0, + max(reference.n_residues, mobile.n_residues), + ) -def fasta2select(fastafilename, is_aligned=False, - ref_resids=None, target_resids=None, - ref_offset=0, target_offset=0, verbosity=3, - alnfilename=None, treefilename=None, clustalw="clustalw2"): +def fasta2select( + fastafilename, + is_aligned=False, + ref_resids=None, + target_resids=None, + ref_offset=0, + target_offset=0, + verbosity=3, + alnfilename=None, + treefilename=None, + clustalw="clustalw2", +): """Return selection strings that will select equivalent residues. The function aligns two sequences provided in a FASTA file and @@ -1307,7 +1400,7 @@ def fasta2select(fastafilename, is_aligned=False, :func:`sequence_alignment`, which does not require external programs. - + Raises ------ ImportError @@ -1325,53 +1418,52 @@ def fasta2select(fastafilename, is_aligned=False, """ if not HAS_BIOPYTHON: - errmsg = ("The `fasta2select` method requires an installation " - "of `Biopython`. Please install `Biopython` to use this " - "method: https://biopython.org/wiki/Download") + errmsg = ( + "The `fasta2select` method requires an installation " + "of `Biopython`. Please install `Biopython` to use this " + "method: https://biopython.org/wiki/Download" + ) raise ImportError(errmsg) if is_aligned: logger.info("Using provided alignment {}".format(fastafilename)) with open(fastafilename) as fasta: - alignment = Bio.AlignIO.read( - fasta, "fasta") + alignment = Bio.AlignIO.read(fasta, "fasta") else: if alnfilename is None: filepath, ext = os.path.splitext(fastafilename) - alnfilename = os.path.basename(filepath) + '.aln' + alnfilename = os.path.basename(filepath) + ".aln" if treefilename is None: filepath, ext = os.path.splitext(alnfilename) - treefilename = os.path.basename(filepath) + '.dnd' + treefilename = os.path.basename(filepath) + ".dnd" run_clustalw = Bio.Align.Applications.ClustalwCommandline( clustalw, infile=fastafilename, type="protein", align=True, outfile=alnfilename, - newtree=treefilename) + newtree=treefilename, + ) logger.debug( - "Aligning sequences in %(fastafilename)r with %(clustalw)r.", - vars()) + "Aligning sequences in %(fastafilename)r with %(clustalw)r.", vars() + ) logger.debug("ClustalW commandline: %r", str(run_clustalw)) try: stdout, stderr = run_clustalw() except: logger.exception("ClustalW %(clustalw)r failed", vars()) - logger.info( - "(You can get clustalw2 from http://www.clustal.org/clustal2/)") + logger.info("(You can get clustalw2 from http://www.clustal.org/clustal2/)") raise with open(alnfilename) as aln: - alignment = Bio.AlignIO.read( - aln, "clustal") - logger.info( - "Using clustalw sequence alignment {0!r}".format(alnfilename)) + alignment = Bio.AlignIO.read(aln, "clustal") + logger.info("Using clustalw sequence alignment {0!r}".format(alnfilename)) logger.info( - "ClustalW Newick guide tree was also produced: {0!r}".format(treefilename)) + "ClustalW Newick guide tree was also produced: {0!r}".format(treefilename) + ) nseq = len(alignment) if nseq != 2: - raise ValueError( - "Only two sequences in the alignment can be processed.") + raise ValueError("Only two sequences in the alignment can be processed.") # implict assertion that we only have two sequences in the alignment orig_resids = [ref_resids, target_resids] @@ -1387,8 +1479,7 @@ def fasta2select(fastafilename, is_aligned=False, else: orig_resids[iseq] = np.asarray(orig_resids[iseq]) # add offsets to the sequence <--> resid translation table - seq2resids = [resids + offset for resids, offset in zip( - orig_resids, offsets)] + seq2resids = [resids + offset for resids, offset in zip(orig_resids, offsets)] del orig_resids del offsets @@ -1424,8 +1515,9 @@ def resid_factory(alignment, seq2resids): t = np.zeros((nseq, alignment.get_alignment_length()), dtype=int) for iseq, a in enumerate(alignment): GAP = "-" - t[iseq, :] = seq2resids[iseq][np.cumsum(np.where( - np.array(list(a.seq)) == GAP, 0, 1)) - 1] + t[iseq, :] = seq2resids[iseq][ + np.cumsum(np.where(np.array(list(a.seq)) == GAP, 0, 1)) - 1 + ] # -1 because seq2resid is index-1 based (resids start at 1) def resid(nseq, ipos, t=t): @@ -1444,7 +1536,7 @@ def resid(nseq, ipos, t=t): if GAP in aligned: continue # skip residue template = "resid %i" - if 'G' not in aligned: + if "G" not in aligned: # can use CB template += " and ( backbone or name CB )" else: @@ -1457,7 +1549,7 @@ def resid(nseq, ipos, t=t): ref_selection = " or ".join(sel[0]) target_selection = " or ".join(sel[1]) - return {'reference': ref_selection, 'mobile': target_selection} + return {"reference": ref_selection, "mobile": target_selection} def get_matching_atoms(ag1, ag2, tol_mass=0.1, strict=False, match_atoms=True): @@ -1535,34 +1627,39 @@ def get_matching_atoms(ag1, ag2, tol_mass=0.1, strict=False, match_atoms=True): if ag1.n_atoms != ag2.n_atoms: if not match_atoms: - errmsg = ("Mobile and reference atom selections do not " - "contain the same number of atoms and atom " - "matching is turned off. To match atoms based " - "on residue and mass, try match_atoms=True") + errmsg = ( + "Mobile and reference atom selections do not " + "contain the same number of atoms and atom " + "matching is turned off. To match atoms based " + "on residue and mass, try match_atoms=True" + ) logger.error(errmsg) raise SelectionError(errmsg) if ag1.n_residues != ag2.n_residues: - errmsg = ("Reference and trajectory atom selections do not contain " - "the same number of atoms: \n" - "atoms: N_ref={0}, N_traj={1}\n" - "and also not the same number of residues:\n" - "residues: N_ref={2}, N_traj={3}").format( - ag1.n_atoms, ag2.n_atoms, - ag1.n_residues, ag2.n_residues) + errmsg = ( + "Reference and trajectory atom selections do not contain " + "the same number of atoms: \n" + "atoms: N_ref={0}, N_traj={1}\n" + "and also not the same number of residues:\n" + "residues: N_ref={2}, N_traj={3}" + ).format(ag1.n_atoms, ag2.n_atoms, ag1.n_residues, ag2.n_residues) logger.error(errmsg) raise SelectionError(errmsg) else: - msg = ("Reference and trajectory atom selections do not contain " - "the same number of atoms: \n" - "atoms: N_ref={0}, N_traj={1}").format( - ag1.n_atoms, ag2.n_atoms) + msg = ( + "Reference and trajectory atom selections do not contain " + "the same number of atoms: \n" + "atoms: N_ref={0}, N_traj={1}" + ).format(ag1.n_atoms, ag2.n_atoms) if strict: logger.error(msg) raise SelectionError(msg) # continue with trying to create a valid selection - msg += ("\nbut we attempt to create a valid selection " + - "(use strict=True to disable this heuristic).") + msg += ( + "\nbut we attempt to create a valid selection " + + "(use strict=True to disable this heuristic)." + ) logger.info(msg) warnings.warn(msg, category=SelectionWarning) @@ -1590,7 +1687,7 @@ def get_matching_atoms(ag1, ag2, tol_mass=0.1, strict=False, match_atoms=True): rsize1 = np.array([r.atoms.n_atoms for r in ag1.residues]) rsize2 = np.array([r.atoms.n_atoms for r in ag2.residues]) rsize_mismatches = np.absolute(rsize1 - rsize2) - mismatch_mask = (rsize_mismatches > 0) + mismatch_mask = rsize_mismatches > 0 if np.any(mismatch_mask): def get_atoms_byres(g, match_mask=None): @@ -1600,7 +1697,7 @@ def get_atoms_byres(g, match_mask=None): match_mask = np.logical_not(mismatch_mask) ag = g.atoms good = ag.residues.resids[match_mask] # resid for each residue - resids = ag.resids # resid for each atom + resids = ag.resids # resid for each atom # boolean array for all matching atoms ix_good = np.isin(resids, good) return ag[ix_good] @@ -1612,12 +1709,21 @@ def get_atoms_byres(g, match_mask=None): # diagnostics mismatch_resindex = np.arange(ag1.n_residues)[mismatch_mask] - logger.warning("Removed {0} residues with non-matching numbers of atoms" - .format(mismatch_mask.sum())) - logger.debug("Removed residue ids: group 1: {0}" - .format(ag1.residues.resids[mismatch_resindex])) - logger.debug("Removed residue ids: group 2: {0}" - .format(ag2.residues.resids[mismatch_resindex])) + logger.warning( + "Removed {0} residues with non-matching numbers of atoms".format( + mismatch_mask.sum() + ) + ) + logger.debug( + "Removed residue ids: group 1: {0}".format( + ag1.residues.resids[mismatch_resindex] + ) + ) + logger.debug( + "Removed residue ids: group 2: {0}".format( + ag2.residues.resids[mismatch_resindex] + ) + ) # replace after logging (still need old ag1 and ag2 for # diagnostics) ag1 = _ag1 @@ -1626,8 +1732,10 @@ def get_atoms_byres(g, match_mask=None): # stop if we created empty selections (by removing ALL residues...) if ag1.n_atoms == 0 or ag2.n_atoms == 0: - errmsg = ("Failed to automatically find matching atoms: created empty selections. " - "Try to improve your selections for mobile and reference.") + errmsg = ( + "Failed to automatically find matching atoms: created empty selections. " + "Try to improve your selections for mobile and reference." + ) logger.error(errmsg) raise SelectionError(errmsg) @@ -1636,17 +1744,18 @@ def get_atoms_byres(g, match_mask=None): # good and can easily be misled (e.g., when one of the selections # had fewer atoms but the residues in mobile and reference have # each the same number) - if (not hasattr(ag1, 'masses') or not hasattr(ag2, 'masses')): + if not hasattr(ag1, "masses") or not hasattr(ag2, "masses"): msg = "Atoms could not be matched since they don't contain masses." logger.info(msg) warnings.warn(msg, category=SelectionWarning) else: try: - mass_mismatches = (np.absolute(ag1.masses - ag2.masses) > tol_mass) + mass_mismatches = np.absolute(ag1.masses - ag2.masses) > tol_mass except ValueError: - errmsg = ("Failed to find matching atoms: len(reference) = {}, len(mobile) = {} " - "Try to improve your selections for mobile and reference.").format( - ag1.n_atoms, ag2.n_atoms) + errmsg = ( + "Failed to find matching atoms: len(reference) = {}, len(mobile) = {} " + "Try to improve your selections for mobile and reference." + ).format(ag1.n_atoms, ag2.n_atoms) logger.error(errmsg) raise SelectionError(errmsg) from None @@ -1666,9 +1775,13 @@ def get_atoms_byres(g, match_mask=None): at.resid, at.resname, at.name, - at.mass)) - errmsg = ("Inconsistent selections, masses differ by more than {0}; " - "mis-matching atoms are shown above.").format(tol_mass) + at.mass, + ) + ) + errmsg = ( + "Inconsistent selections, masses differ by more than {0}; " + "mis-matching atoms are shown above." + ).format(tol_mass) logger.error(errmsg) raise SelectionError(errmsg) diff --git a/package/MDAnalysis/analysis/atomicdistances.py b/package/MDAnalysis/analysis/atomicdistances.py index 1860d3285b..5cf15128d8 100644 --- a/package/MDAnalysis/analysis/atomicdistances.py +++ b/package/MDAnalysis/analysis/atomicdistances.py @@ -150,15 +150,12 @@ class AtomicDistances(AnalysisBase): def __init__(self, ag1, ag2, pbc=True, **kwargs): # check ag1 and ag2 have the same number of atoms if ag1.atoms.n_atoms != ag2.atoms.n_atoms: - raise ValueError("AtomGroups do not " - "have the same number of atoms") + raise ValueError("AtomGroups do not " "have the same number of atoms") # check ag1 and ag2 are from the same trajectory elif ag1.universe.trajectory != ag2.universe.trajectory: - raise ValueError("AtomGroups are not " - "from the same trajectory") + raise ValueError("AtomGroups are not " "from the same trajectory") - super(AtomicDistances, self).__init__(ag1.universe.trajectory, - **kwargs) + super(AtomicDistances, self).__init__(ag1.universe.trajectory, **kwargs) self._ag1 = ag1 self._ag2 = ag2 @@ -171,6 +168,6 @@ def _prepare(self): def _single_frame(self): # if PBCs considered, get box size box = self._ag1.dimensions if self._pbc else None - self.results[self._frame_index] = calc_bonds(self._ag1.positions, - self._ag2.positions, - box) + self.results[self._frame_index] = calc_bonds( + self._ag1.positions, self._ag2.positions, box + ) diff --git a/package/MDAnalysis/analysis/base.py b/package/MDAnalysis/analysis/base.py index f18b866951..80c390fd46 100644 --- a/package/MDAnalysis/analysis/base.py +++ b/package/MDAnalysis/analysis/base.py @@ -387,14 +387,10 @@ def _define_run_frames( self._trajectory = trajectory if frames is not None: if not all(opt is None for opt in [start, stop, step]): - raise ValueError( - "start/stop/step cannot be combined with frames" - ) + raise ValueError("start/stop/step cannot be combined with frames") slicer = frames else: - start, stop, step = trajectory.check_slice_indices( - start, stop, step - ) + start, stop, step = trajectory.check_slice_indices(start, stop, step) slicer = slice(start, stop, step) self.start, self.stop, self.step = start, stop, step return slicer @@ -417,9 +413,7 @@ def _prepare_sliced_trajectory(self, slicer: Union[slice, np.ndarray]): self.frames = np.zeros(self.n_frames, dtype=int) self.times = np.zeros(self.n_frames) - def _setup_frames( - self, trajectory, start=None, stop=None, step=None, frames=None - ): + def _setup_frames(self, trajectory, start=None, stop=None, step=None, frames=None): """Pass a Reader object and define the desired iteration pattern through the trajectory @@ -539,9 +533,7 @@ def _compute( progressbar_kwargs = {} logger.info("Choosing frames to analyze") # if verbose unchanged, use class default - verbose = ( - getattr(self, "_verbose", False) if verbose is None else verbose - ) + verbose = getattr(self, "_verbose", False) if verbose is None else verbose frames = indexed_frames[:, 1] @@ -552,9 +544,7 @@ def _compute( return self for idx, ts in enumerate( - ProgressBar( - self._sliced_trajectory, verbose=verbose, **progressbar_kwargs - ) + ProgressBar(self._sliced_trajectory, verbose=verbose, **progressbar_kwargs) ): self._frame_index = idx # accessed later by subclasses self._ts = ts @@ -607,9 +597,7 @@ def _setup_computation_groups( .. versionadded:: 2.8.0 """ if frames is None: - start, stop, step = self._trajectory.check_slice_indices( - start, stop, step - ) + start, stop, step = self._trajectory.check_slice_indices(start, stop, step) used_frames = np.arange(start, stop, step) elif not all(opt is None for opt in [start, stop, step]): raise ValueError("start/stop/step cannot be combined with frames") @@ -621,9 +609,7 @@ def _setup_computation_groups( used_frames = arange[used_frames] # similar to list(enumerate(frames)) - enumerated_frames = np.vstack( - [np.arange(len(used_frames)), used_frames] - ).T + enumerated_frames = np.vstack([np.arange(len(used_frames)), used_frames]).T if len(enumerated_frames) == 0: return [np.empty((0, 2), dtype=np.int64)] elif len(enumerated_frames) < n_parts: @@ -745,9 +731,7 @@ def _configure_backend( # or pass along an instance of the class itself # after ensuring it has apply method - if not isinstance(backend, BackendBase) or not hasattr( - backend, "apply" - ): + if not isinstance(backend, BackendBase) or not hasattr(backend, "apply"): raise ValueError( ( f"{backend=} is invalid: should have 'apply' method " @@ -835,23 +819,18 @@ def run( # default to serial execution backend = "serial" if backend is None else backend - progressbar_kwargs = ( - {} if progressbar_kwargs is None else progressbar_kwargs - ) + progressbar_kwargs = {} if progressbar_kwargs is None else progressbar_kwargs if (progressbar_kwargs or verbose) and not ( backend == "serial" or isinstance(backend, BackendSerial) ): - raise ValueError( - "Can not display progressbar with non-serial backend" - ) + raise ValueError("Can not display progressbar with non-serial backend") # if number of workers not specified, try getting the number from # the backend instance if possible, or set to 1 if n_workers is None: n_workers = ( backend.n_workers - if isinstance(backend, BackendBase) - and hasattr(backend, "n_workers") + if isinstance(backend, BackendBase) and hasattr(backend, "n_workers") else 1 ) @@ -1016,9 +995,7 @@ def _get_aggregator(self): return ResultsGroup({"timeseries": ResultsGroup.flatten_sequence}) def _single_frame(self): - self.results.timeseries.append( - self.function(*self.args, **self.kwargs) - ) + self.results.timeseries.append(self.function(*self.args, **self.kwargs)) def _conclude(self): self.results.frames = self.frames @@ -1079,9 +1056,7 @@ def RotationMatrix(mobile, ref): class WrapperClass(AnalysisFromFunction): def __init__(self, trajectory=None, *args, **kwargs): - super(WrapperClass, self).__init__( - function, trajectory, *args, **kwargs - ) + super(WrapperClass, self).__init__(function, trajectory, *args, **kwargs) @classmethod def get_supported_backends(cls): diff --git a/package/MDAnalysis/analysis/bat.py b/package/MDAnalysis/analysis/bat.py index 9b08c7dbff..0e2adbc056 100644 --- a/package/MDAnalysis/analysis/bat.py +++ b/package/MDAnalysis/analysis/bat.py @@ -216,9 +216,7 @@ def _find_torsions(root, atoms): for a1 in selected_atoms: # Find a0, which is a new atom connected to the selected atom a0_list = _sort_atoms_by_mass( - a - for a in a1.bonded_atoms - if (a in atoms) and (a not in selected_atoms) + a for a in a1.bonded_atoms if (a in atoms) and (a not in selected_atoms) ) for a0 in a0_list: # Find a2, which is connected to a1, is not a terminal atom, @@ -381,9 +379,7 @@ def __init__(self, ag, initial_atom=None, filename=None, **kwargs): self._primary_torsion_indices = [ prior_atoms.index(prior_atoms[n]) for n in range(len(prior_atoms)) ] - self._unique_primary_torsion_indices = list( - set(self._primary_torsion_indices) - ) + self._unique_primary_torsion_indices = list(set(self._primary_torsion_indices)) self._ag1 = mda.AtomGroup([ag[0] for ag in self._torsions]) self._ag2 = mda.AtomGroup([ag[1] for ag in self._torsions]) @@ -422,8 +418,7 @@ def _single_frame(self): 1.0, np.einsum("i,i->", v01, v21) / np.sqrt( - np.einsum("i,i->", v01, v01) - * np.einsum("i,i->", v21, v21) + np.einsum("i,i->", v01, v01) * np.einsum("i,i->", v21, v21) ), ), ) @@ -437,9 +432,7 @@ def _single_frame(self): sp = np.sin(phi) ct = np.cos(theta) st = np.sin(theta) - Rz = np.array( - [[cp * ct, ct * sp, -st], [-sp, cp, 0], [cp * st, sp * st, ct]] - ) + Rz = np.array([[cp * ct, ct * sp, -st], [-sp, cp, 0], [cp * st, sp * st, ct]]) pos2 = Rz.dot(p2 - p1) # Angle about the rotation axis omega = np.arctan2(pos2[1], pos2[0]) @@ -576,9 +569,7 @@ def Cartesian(self, bat_frame): ct = np.cos(theta) st = np.sin(theta) # $R_Z(\phi) R_Y(\theta)$ - Re = np.array( - [[cp * ct, -sp, cp * st], [ct * sp, cp, sp * st], [-st, 0, ct]] - ) + Re = np.array([[cp * ct, -sp, cp * st], [ct * sp, cp, sp * st], [-st, 0, ct]]) p1 = Re.dot(p1) p2 = Re.dot(p2) # Translate the first three atoms by the origin diff --git a/package/MDAnalysis/analysis/contacts.py b/package/MDAnalysis/analysis/contacts.py index 5d63471ae7..9956967fac 100644 --- a/package/MDAnalysis/analysis/contacts.py +++ b/package/MDAnalysis/analysis/contacts.py @@ -451,9 +451,7 @@ def __init__( elif method == "soft_cut": self.fraction_contacts = soft_cut_q elif method == "radius_cut": - self.fraction_contacts = functools.partial( - radius_cut_q, radius=radius - ) + self.fraction_contacts = functools.partial(radius_cut_q, radius=radius) else: if not callable(method): raise ValueError("method has to be callable") @@ -492,9 +490,7 @@ def __init__( box=self._get_box(refA.universe), ) ) - self.initial_contacts.append( - contact_matrix(self.r0[-1], radius) - ) + self.initial_contacts.append(contact_matrix(self.r0[-1], radius)) self.n_initial_contacts = self.initial_contacts[0].sum() diff --git a/package/MDAnalysis/analysis/density.py b/package/MDAnalysis/analysis/density.py index 61c4e67989..aa4df1b9ce 100644 --- a/package/MDAnalysis/analysis/density.py +++ b/package/MDAnalysis/analysis/density.py @@ -439,9 +439,7 @@ def __init__( # in _prepare(), which is executed in parallel on different # parts of the trajectory). coord = self._atomgroup.positions - if self._gridcenter is not None or any( - [self._xdim, self._ydim, self._zdim] - ): + if self._gridcenter is not None or any([self._xdim, self._ydim, self._zdim]): # Issue 2372: padding is ignored, defaults to 2.0 therefore warn if self._padding > 0: msg = ( @@ -804,24 +802,17 @@ def _check_set_unit(self, u): # all this unit crap should be a class... try: for unit_type, value in u.items(): - if ( - value is None - ): # check here, too iffy to use dictionary[None]=None + if value is None: # check here, too iffy to use dictionary[None]=None self.units[unit_type] = None continue try: units.conversion_factor[unit_type][value] self.units[unit_type] = value except KeyError: - errmsg = ( - f"Unit {value} of type {unit_type} is not " - f"recognized." - ) + errmsg = f"Unit {value} of type {unit_type} is not " f"recognized." raise ValueError(errmsg) from None except AttributeError: - errmsg = ( - '"unit" must be a dictionary with keys "length" and "density.' - ) + errmsg = '"unit" must be a dictionary with keys "length" and "density.' logger.fatal(errmsg) raise ValueError(errmsg) from None # need at least length and density (can be None) @@ -878,9 +869,7 @@ def convert_length(self, unit="Angstrom"): """ if unit == self.units["length"]: return - cvnfact = units.get_conversion_factor( - "length", self.units["length"], unit - ) + cvnfact = units.get_conversion_factor("length", self.units["length"], unit) self.edges = [x * cvnfact for x in self.edges] self.units["length"] = unit self._update() # needed to recalculate midpoints and origin @@ -947,10 +936,4 @@ def __repr__(self): grid_type = "density" else: grid_type = "histogram" - return ( - "" - ) + return "" diff --git a/package/MDAnalysis/analysis/diffusionmap.py b/package/MDAnalysis/analysis/diffusionmap.py index 65330196ec..3817835ddd 100644 --- a/package/MDAnalysis/analysis/diffusionmap.py +++ b/package/MDAnalysis/analysis/diffusionmap.py @@ -235,16 +235,25 @@ class DistanceMatrix(AnalysisBase): :class:`DistanceMatrix` is now correctly works with `frames=...` parameter (#4432) by iterating over `self._sliced_trajectory` """ - def __init__(self, universe, select='all', metric=rmsd, cutoff=1E0-5, - weights=None, **kwargs): + + def __init__( + self, + universe, + select="all", + metric=rmsd, + cutoff=1e0 - 5, + weights=None, + **kwargs + ): # remember that this must be called before referencing self.n_frames - super(DistanceMatrix, self).__init__(universe.universe.trajectory, - **kwargs) + super(DistanceMatrix, self).__init__(universe.universe.trajectory, **kwargs) if isinstance(universe, UpdatingAtomGroup): - wmsg = ("U must be a static AtomGroup. Parsing an updating AtomGroup " - "will result in a static AtomGroup with the current frame " - "atom selection.") + wmsg = ( + "U must be a static AtomGroup. Parsing an updating AtomGroup " + "will result in a static AtomGroup with the current frame " + "atom selection." + ) warnings.warn(wmsg) self.atoms = universe.select_atoms(select) @@ -266,20 +275,21 @@ def _single_frame(self): self._ts = ts j_ref = self.atoms.positions dist = self._metric(i_ref, j_ref, weights=self._weights) - self.results.dist_matrix[self._frame_index, - j+self._frame_index] = ( - dist if dist > self._cutoff else 0) - self.results.dist_matrix[j+self._frame_index, - self._frame_index] = ( - self.results.dist_matrix[self._frame_index, - j+self._frame_index]) + self.results.dist_matrix[self._frame_index, j + self._frame_index] = ( + dist if dist > self._cutoff else 0 + ) + self.results.dist_matrix[j + self._frame_index, self._frame_index] = ( + self.results.dist_matrix[self._frame_index, j + self._frame_index] + ) self._ts = self._sliced_trajectory[iframe] @property def dist_matrix(self): - wmsg = ("The `dist_matrix` attribute was deprecated in " - "MDAnalysis 2.0.0 and will be removed in MDAnalysis 3.0.0. " - "Please use `results.dist_matrix` instead.") + wmsg = ( + "The `dist_matrix` attribute was deprecated in " + "MDAnalysis 2.0.0 and will be removed in MDAnalysis 3.0.0. " + "Please use `results.dist_matrix` instead." + ) warnings.warn(wmsg, DeprecationWarning) return self.results.dist_matrix @@ -334,12 +344,14 @@ def __init__(self, u, epsilon=1, **kwargs): elif isinstance(u, DistanceMatrix): self._dist_matrix = u else: - raise ValueError("U is not a Universe or AtomGroup or DistanceMatrix and" - " so the DiffusionMap has no data to work with.") + raise ValueError( + "U is not a Universe or AtomGroup or DistanceMatrix and" + " so the DiffusionMap has no data to work with." + ) self._epsilon = epsilon def run(self, start=None, stop=None, step=None): - """ Create and decompose the diffusion matrix in preparation + """Create and decompose the diffusion matrix in preparation for a diffusion map. Parameters @@ -360,11 +372,12 @@ def run(self, start=None, stop=None, step=None): # important for transform function and length of .run() method self._n_frames = self._dist_matrix.n_frames if self._n_frames > 5000: - warnings.warn("The distance matrix is very large, and can " - "be very slow to compute. Consider picking a larger " - "step size in distance matrix initialization.") - self._scaled_matrix = (self._dist_matrix.results.dist_matrix ** 2 / - self._epsilon) + warnings.warn( + "The distance matrix is very large, and can " + "be very slow to compute. Consider picking a larger " + "step size in distance matrix initialization." + ) + self._scaled_matrix = self._dist_matrix.results.dist_matrix**2 / self._epsilon # take negative exponent of scaled matrix to create Isotropic kernel self._kernel = np.exp(-self._scaled_matrix) D_inv = np.diag(1 / self._kernel.sum(1)) @@ -377,7 +390,7 @@ def run(self, start=None, stop=None, step=None): return self def transform(self, n_eigenvectors, time): - """ Embeds a trajectory via the diffusion map + """Embeds a trajectory via the diffusion map Parameters --------- @@ -392,5 +405,6 @@ def transform(self, n_eigenvectors, time): diffusion_space : array (n_frames, n_eigenvectors) The diffusion map embedding as defined by :footcite:p:`Ferguson2011`. """ - return (self._eigenvectors[1:n_eigenvectors+1,].T * - (self.eigenvalues[1:n_eigenvectors+1]**time)) + return self._eigenvectors[1 : n_eigenvectors + 1,].T * ( + self.eigenvalues[1 : n_eigenvectors + 1] ** time + ) diff --git a/package/MDAnalysis/analysis/dihedrals.py b/package/MDAnalysis/analysis/dihedrals.py index 0c5ecb33cd..9eaa3ba9cb 100644 --- a/package/MDAnalysis/analysis/dihedrals.py +++ b/package/MDAnalysis/analysis/dihedrals.py @@ -295,9 +295,7 @@ def __init__(self, atomgroups, **kwargs): If any atomgroups do not contain 4 atoms """ - super(Dihedral, self).__init__( - atomgroups[0].universe.trajectory, **kwargs - ) + super(Dihedral, self).__init__(atomgroups[0].universe.trajectory, **kwargs) self.atomgroups = atomgroups if any([len(ag) != 4 for ag in atomgroups]): @@ -425,9 +423,7 @@ def __init__( check_protein=True, **kwargs, ): - super(Ramachandran, self).__init__( - atomgroup.universe.trajectory, **kwargs - ) + super(Ramachandran, self).__init__(atomgroup.universe.trajectory, **kwargs) self.atomgroup = atomgroup residues = self.atomgroup.residues @@ -454,8 +450,7 @@ def __init__( if not np.all(keep): warnings.warn( - "Some residues in selection do not have " - "phi or psi selections" + "Some residues in selection do not have " "phi or psi selections" ) prev = sum(prev[keep]) nxt = sum(nxt[keep]) @@ -464,9 +459,7 @@ def __init__( # find n, c, ca keep_prev = [sum(r.atoms.names == c_name) == 1 for r in prev] rnames = [n_name, c_name, ca_name] - keep_res = [ - all(sum(r.atoms.names == n) == 1 for n in rnames) for r in residues - ] + keep_res = [all(sum(r.atoms.names == n) == 1 for n in rnames) for r in residues] keep_next = [sum(r.atoms.names == n_name) == 1 for r in nxt] # alright we'll keep these @@ -545,22 +538,16 @@ def plot(self, ax=None, ref=False, **kwargs): xlabel=r"$\phi$", ylabel=r"$\psi$", ) - degree_formatter = plt.matplotlib.ticker.StrMethodFormatter( - r"{x:g}$\degree$" - ) + degree_formatter = plt.matplotlib.ticker.StrMethodFormatter(r"{x:g}$\degree$") ax.xaxis.set_major_formatter(degree_formatter) ax.yaxis.set_major_formatter(degree_formatter) if ref: - X, Y = np.meshgrid( - np.arange(-180, 180, 4), np.arange(-180, 180, 4) - ) + X, Y = np.meshgrid(np.arange(-180, 180, 4), np.arange(-180, 180, 4)) levels = [1, 17, 15000] colors = ["#A1D4FF", "#35A1FF"] ax.contourf(X, Y, np.load(Rama_ref), levels=levels, colors=colors) - a = self.results.angles.reshape( - np.prod(self.results.angles.shape[:2]), 2 - ) + a = self.results.angles.reshape(np.prod(self.results.angles.shape[:2]), 2) ax.scatter(a[:, 0], a[:, 1], **kwargs) return ax @@ -637,9 +624,7 @@ def __init__( :attr:`angles` results are now stored in a :class:`MDAnalysis.analysis.base.Results` instance. """ - super(Ramachandran, self).__init__( - atomgroup.universe.trajectory, **kwargs - ) + super(Ramachandran, self).__init__(atomgroup.universe.trajectory, **kwargs) self.atomgroup = atomgroup residues = atomgroup.residues protein = atomgroup.select_atoms(select_protein).residues @@ -669,8 +654,7 @@ def __init__( # must be removed before using the class, or the file is missing atoms # for some residues which must also be removed if any( - len(self.ag1) != len(ag) - for ag in [self.ag2, self.ag3, self.ag4, self.ag5] + len(self.ag1) != len(ag) for ag in [self.ag2, self.ag3, self.ag4, self.ag5] ): raise ValueError( "Too many or too few atoms selected. Check for " @@ -678,9 +662,7 @@ def __init__( ) def _conclude(self): - self.results.angles = ( - np.rad2deg(np.array(self.results.angles)) + 360 - ) % 360 + self.results.angles = (np.rad2deg(np.array(self.results.angles)) + 360) % 360 def plot(self, ax=None, ref=False, **kwargs): """Plots data into standard Janin plot. @@ -718,9 +700,7 @@ def plot(self, ax=None, ref=False, **kwargs): xlabel=r"$\chi_1$", ylabel=r"$\chi_2$", ) - degree_formatter = plt.matplotlib.ticker.StrMethodFormatter( - r"{x:g}$\degree$" - ) + degree_formatter = plt.matplotlib.ticker.StrMethodFormatter(r"{x:g}$\degree$") ax.xaxis.set_major_formatter(degree_formatter) ax.yaxis.set_major_formatter(degree_formatter) @@ -729,8 +709,6 @@ def plot(self, ax=None, ref=False, **kwargs): levels = [1, 6, 600] colors = ["#A1D4FF", "#35A1FF"] ax.contourf(X, Y, np.load(Janin_ref), levels=levels, colors=colors) - a = self.results.angles.reshape( - np.prod(self.results.angles.shape[:2]), 2 - ) + a = self.results.angles.reshape(np.prod(self.results.angles.shape[:2]), 2) ax.scatter(a[:, 0], a[:, 1], **kwargs) return ax diff --git a/package/MDAnalysis/analysis/distances.py b/package/MDAnalysis/analysis/distances.py index 44a09c4fcb..604ab53f6b 100644 --- a/package/MDAnalysis/analysis/distances.py +++ b/package/MDAnalysis/analysis/distances.py @@ -168,9 +168,7 @@ def dist(A, B, offset=0, box=None): """ if A.atoms.n_atoms != B.atoms.n_atoms: - raise ValueError( - "AtomGroups A and B do not have the same number of atoms" - ) + raise ValueError("AtomGroups A and B do not have the same number of atoms") try: off_A, off_B = offset except (TypeError, ValueError): diff --git a/package/MDAnalysis/analysis/dssp/dssp.py b/package/MDAnalysis/analysis/dssp/dssp.py index d88f1bdbe4..b1aef1bd0a 100644 --- a/package/MDAnalysis/analysis/dssp/dssp.py +++ b/package/MDAnalysis/analysis/dssp/dssp.py @@ -316,8 +316,7 @@ def __init__( for t in heavyatom_names } self._hydrogens: list["AtomGroup"] = [ - res.atoms.select_atoms(f"name {hydrogen_name}") - for res in ag.residues + res.atoms.select_atoms(f"name {hydrogen_name}") for res in ag.residues ] # can't do it the other way because I need missing values to exist # so that I could fill them in later @@ -373,9 +372,7 @@ def _get_coords(self) -> np.ndarray: coords = np.array(positions) if not self._guess_hydrogens: - guessed_h_coords = _get_hydrogen_atom_position( - coords.swapaxes(0, 1) - ) + guessed_h_coords = _get_hydrogen_atom_position(coords.swapaxes(0, 1)) h_coords = np.array( [ diff --git a/package/MDAnalysis/analysis/dssp/pydssp_numpy.py b/package/MDAnalysis/analysis/dssp/pydssp_numpy.py index f54ea5443a..1ae8ac369e 100644 --- a/package/MDAnalysis/analysis/dssp/pydssp_numpy.py +++ b/package/MDAnalysis/analysis/dssp/pydssp_numpy.py @@ -65,10 +65,7 @@ def _upsample(a: np.ndarray, window: int) -> np.ndarray: def _unfold(a: np.ndarray, window: int, axis: int): "Helper function for 2D array upsampling" - idx = ( - np.arange(window)[:, None] - + np.arange(a.shape[axis] - window + 1)[None, :] - ) + idx = np.arange(window)[:, None] + np.arange(a.shape[axis] - window + 1)[None, :] unfolded = np.take(a, idx, axis=axis) return np.moveaxis(unfolded, axis - 1, -1) @@ -157,9 +154,7 @@ def get_hbond_map( h_1 = coord[1:, 4] coord = coord[:, :4] else: # pragma: no cover - raise ValueError( - "Number of atoms should be 4 (N,CA,C,O) or 5 (N,CA,C,O,H)" - ) + raise ValueError("Number of atoms should be 4 (N,CA,C,O) or 5 (N,CA,C,O,H)") # after this: # h.shape == (n_atoms, 3) # coord.shape == (n_atoms, 4, 3) @@ -181,9 +176,7 @@ def get_hbond_map( # electrostatic interaction energy # e[i, j] = e(CO_i) - e(NH_j) e = np.pad( - CONST_Q1Q2 - * (1.0 / d_on + 1.0 / d_ch - 1.0 / d_oh - 1.0 / d_cn) - * CONST_F, + CONST_Q1Q2 * (1.0 / d_on + 1.0 / d_ch - 1.0 / d_oh - 1.0 / d_cn) * CONST_F, [[1, 0], [0, 1]], ) diff --git a/package/MDAnalysis/analysis/encore/bootstrap.py b/package/MDAnalysis/analysis/encore/bootstrap.py index 8784409c7f..48bdf8c98c 100644 --- a/package/MDAnalysis/analysis/encore/bootstrap.py +++ b/package/MDAnalysis/analysis/encore/bootstrap.py @@ -116,9 +116,7 @@ def get_distance_matrix_bootstrap_samples( confdistmatrix : list of encore.utils.TriangularMatrix """ - bs_args = [ - ([distance_matrix, ensemble_assignment]) for i in range(samples) - ] + bs_args = [([distance_matrix, ensemble_assignment]) for i in range(samples)] pc = ParallelCalculation(ncores, bootstrapped_matrix, bs_args) diff --git a/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py b/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py index 8c545c5421..cde3cbff95 100644 --- a/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py +++ b/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py @@ -99,9 +99,7 @@ def __init__(self, elem_list=None, centroid=None, idn=None, metadata=None): self.metadata = {} self.elements = elem_list if centroid not in self.elements: - raise LookupError( - "Centroid of cluster not found in the element list" - ) + raise LookupError("Centroid of cluster not found in the element list") self.centroid = centroid self.size = self.elements.shape[0] @@ -130,8 +128,7 @@ def __len__(self): def add_metadata(self, name, data): if len(data) != self.size: raise TypeError( - "Size of metadata is not equal to the number of " - "cluster elements" + "Size of metadata is not equal to the number of " "cluster elements" ) self.metadata[name] = np.array(data) @@ -270,6 +267,4 @@ def __repr__(self): if self.clusters is None: return "" else: - return "".format( - len(self.clusters) - ) + return "".format(len(self.clusters)) diff --git a/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py b/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py index 9af8d48fa8..8aff6e3815 100644 --- a/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py +++ b/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py @@ -96,9 +96,7 @@ def __call__(self, x): """ raise NotImplementedError( - "Class {0} doesn't implement __call__()".format( - self.__class__.__name__ - ) + "Class {0} doesn't implement __call__()".format(self.__class__.__name__) ) @@ -247,17 +245,13 @@ def __call__(self, distance_matrix): This method no longer returns ``details`` """ logging.info( - "Starting Affinity Propagation: {0}".format( - self.ap.get_params() - ) + "Starting Affinity Propagation: {0}".format(self.ap.get_params()) ) # Convert from distance matrix to similarity matrix similarity_matrix = distance_matrix.as_array() * -1 clusters = self.ap.fit_predict(similarity_matrix) - clusters = encode_centroid_info( - clusters, self.ap.cluster_centers_indices_ - ) + clusters = encode_centroid_info(clusters, self.ap.cluster_centers_indices_) return clusters @@ -332,9 +326,7 @@ def __call__(self, distance_matrix): .. versionchanged:: 1.0.0 This method no longer returns ``details`` """ - logging.info( - "Starting DBSCAN: {0}".format(self.dbscan.get_params()) - ) + logging.info("Starting DBSCAN: {0}".format(self.dbscan.get_params())) clusters = self.dbscan.fit_predict(distance_matrix.as_array()) if np.min(clusters == -1): clusters += 1 @@ -444,9 +436,7 @@ def __call__(self, coordinates): .. versionchanged:: 1.0.0 This method no longer returns ``details`` """ - logging.info( - "Starting Kmeans: {0}".format((self.kmeans.get_params())) - ) + logging.info("Starting Kmeans: {0}".format((self.kmeans.get_params()))) clusters = self.kmeans.fit_predict(coordinates) distances = self.kmeans.transform(coordinates) cluster_center_indices = np.argmin(distances, axis=0) diff --git a/package/MDAnalysis/analysis/encore/clustering/cluster.py b/package/MDAnalysis/analysis/encore/clustering/cluster.py index 2173a8d207..2aba87e3ef 100644 --- a/package/MDAnalysis/analysis/encore/clustering/cluster.py +++ b/package/MDAnalysis/analysis/encore/clustering/cluster.py @@ -190,9 +190,7 @@ def cluster( if distance_matrix: if not hasattr(distance_matrix, "__iter__"): distance_matrix = [distance_matrix] - if ensembles is not None and len(distance_matrix) != len( - merged_ensembles - ): + if ensembles is not None and len(distance_matrix) != len(merged_ensembles): raise ValueError( "Dimensions of provided list of distance matrices " "does not match that of provided list of " @@ -207,9 +205,7 @@ def cluster( distance_matrix = [] for merged_ensemble in merged_ensembles: distance_matrix.append( - get_distance_matrix( - merged_ensemble, select=select, **kwargs - ) + get_distance_matrix(merged_ensemble, select=select, **kwargs) ) args = [] @@ -218,14 +214,10 @@ def cluster( args += [(d,) for d in distance_matrix] else: for merged_ensemble in merged_ensembles: - coordinates = merged_ensemble.trajectory.timeseries( - order="fac" - ) + coordinates = merged_ensemble.trajectory.timeseries(order="fac") # Flatten coordinate matrix into n_frame x n_coordinates - coordinates = np.reshape( - coordinates, (coordinates.shape[0], -1) - ) + coordinates = np.reshape(coordinates, (coordinates.shape[0], -1)) args.append((coordinates,)) @@ -246,10 +238,7 @@ def cluster( # Create clusters collections from clustering results, # one for each cluster. None if clustering didn't work. - ccs = [ - ClusterCollection(clusters[1], metadata=metadata) - for clusters in results - ] + ccs = [ClusterCollection(clusters[1], metadata=metadata) for clusters in results] if allow_collapsed_result and len(ccs) == 1: ccs = ccs[0] diff --git a/package/MDAnalysis/analysis/encore/confdistmatrix.py b/package/MDAnalysis/analysis/encore/confdistmatrix.py index 95b22bf056..6156aa2cc9 100644 --- a/package/MDAnalysis/analysis/encore/confdistmatrix.py +++ b/package/MDAnalysis/analysis/encore/confdistmatrix.py @@ -112,9 +112,7 @@ def conformational_distance_matrix( # framesn: number of frames framesn = len( - ensemble.trajectory.timeseries( - ensemble.select_atoms(select), order="fac" - ) + ensemble.trajectory.timeseries(ensemble.select_atoms(select), order="fac") ) # Prepare metadata recarray @@ -162,29 +160,20 @@ def conformational_distance_matrix( else: fitting_coordinates = None - if ( - not isinstance(weights, (list, tuple, np.ndarray)) - and weights == "mass" - ): + if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": weights = ensemble.select_atoms(select).masses.astype(np.float64) if pairwise_align: - subset_weights = ensemble.select_atoms( - subset_select - ).masses.astype(np.float64) + subset_weights = ensemble.select_atoms(subset_select).masses.astype( + np.float64 + ) else: subset_weights = None elif weights is None: weights = np.ones( - ( - ensemble.trajectory.timeseries(ensemble.select_atoms(select))[ - 0 - ].shape[0] - ) + (ensemble.trajectory.timeseries(ensemble.select_atoms(select))[0].shape[0]) ).astype(np.float64) if pairwise_align: - subset_weights = np.ones((fit_coords[0].shape[0])).astype( - np.float64 - ) + subset_weights = np.ones((fit_coords[0].shape[0])).astype(np.float64) else: subset_weights = None else: @@ -291,9 +280,7 @@ def set_rmsd_matrix_elements( com_j = np.average(fit_coords[j], axis=0, weights=fit_weights) translated_j = coords[j] - com_j subset2_coords = fit_coords[j] - com_j - rotamat = rotation_matrix( - subset1_coords, subset2_coords, subset_weights - )[0] + rotamat = rotation_matrix(subset1_coords, subset2_coords, subset_weights)[0] rotated_i = np.transpose(np.dot(rotamat, np.transpose(translated_i))) rmsdmat[(i + 1) * i // 2 + j] = PureRMSD( rotated_i.astype(np.float64), @@ -375,9 +362,7 @@ def get_distance_matrix( # Load the matrix if required if load_matrix: - logging.info( - " Loading similarity matrix from: {0}".format(load_matrix) - ) + logging.info(" Loading similarity matrix from: {0}".format(load_matrix)) confdistmatrix = TriangularMatrix( size=ensemble.trajectory.timeseries( ensemble.select_atoms(select), order="fac" @@ -387,9 +372,7 @@ def get_distance_matrix( logging.info(" Done!") for key in confdistmatrix.metadata.dtype.names: logging.info( - " {0} : {1}".format( - key, str(confdistmatrix.metadata[key][0]) - ) + " {0} : {1}".format(key, str(confdistmatrix.metadata[key][0])) ) # Check matrix size for consistency @@ -411,26 +394,17 @@ def get_distance_matrix( # Transfer universe to memory to ensure timeseries() support ensemble.transfer_to_memory() - if ( - not isinstance(weights, (list, tuple, np.ndarray)) - and weights == "mass" - ): + if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": weight_type = "Mass" elif weights is None: weight_type = "None" else: weight_type = "Custom" - logging.info( - " Perform pairwise alignment: {0}".format(str(superimpose)) - ) - logging.info( - " weighted alignment and RMSD: {0}".format(weight_type) - ) + logging.info(" Perform pairwise alignment: {0}".format(str(superimpose))) + logging.info(" weighted alignment and RMSD: {0}".format(weight_type)) if superimpose: logging.info( - " Atoms subset for alignment: {0}".format( - superimposition_subset - ) + " Atoms subset for alignment: {0}".format(superimposition_subset) ) logging.info(" Calculating similarity matrix . . .") diff --git a/package/MDAnalysis/analysis/encore/covariance.py b/package/MDAnalysis/analysis/encore/covariance.py index 08e014e315..727706f5dd 100644 --- a/package/MDAnalysis/analysis/encore/covariance.py +++ b/package/MDAnalysis/analysis/encore/covariance.py @@ -151,18 +151,14 @@ def shrinkage_covariance_estimator( p = 1 / float(t) * np.sum(np.dot(np.transpose(y), y)) - np.sum( np.sum(sample**2) ) - rdiag = 1 / float(t) * np.sum(np.sum(y**2)) - np.sum( - np.diag(sample) ** 2 - ) + rdiag = 1 / float(t) * np.sum(np.sum(y**2)) - np.sum(np.diag(sample) ** 2) z = x * np.repeat(xmkt[:, np.newaxis], n, axis=1) v1 = ( 1 / float(t) * np.dot(np.transpose(y), z) - np.repeat(covmkt[:, np.newaxis], n, axis=1) * sample ) roff1 = ( - np.sum( - v1 * np.transpose(np.repeat(covmkt[:, np.newaxis], n, axis=1)) - ) + np.sum(v1 * np.transpose(np.repeat(covmkt[:, np.newaxis], n, axis=1))) / varmkt - np.sum(np.diag(v1) * covmkt) / varmkt ) @@ -240,10 +236,7 @@ def covariance_matrix( # Optionally correct with weights if weights is not None: # Calculate mass-weighted covariance matrix - if ( - not isinstance(weights, (list, tuple, np.ndarray)) - and weights == "mass" - ): + if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": if select: weights = ensemble.select_atoms(select).masses else: @@ -255,8 +248,7 @@ def covariance_matrix( req_len = ensemble.atoms.n_atoms if req_len != len(weights): raise ValueError( - "number of weights is unequal to number of " - "atoms in ensemble" + "number of weights is unequal to number of " "atoms in ensemble" ) # broadcast to a (len(weights), 3) array diff --git a/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py b/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py index 3ca43202f5..4005e59673 100644 --- a/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py +++ b/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py @@ -85,9 +85,7 @@ def __call__(self, x): """ raise NotImplementedError( - "Class {0} doesn't implement __call__()".format( - self.__class__.__name__ - ) + "Class {0} doesn't implement __call__()".format(self.__class__.__name__) ) @@ -150,17 +148,15 @@ def __call__(self, distance_matrix): coordinates in reduced space """ - final_stress, coordinates = ( - stochasticproxembed.StochasticProximityEmbedding( - s=distance_matrix, - rco=self.distance_cutoff, - dim=self.dimension, - minlam=self.min_lam, - maxlam=self.max_lam, - ncycle=self.ncycle, - nstep=self.nstep, - stressfreq=self.stressfreq, - ) + final_stress, coordinates = stochasticproxembed.StochasticProximityEmbedding( + s=distance_matrix, + rco=self.distance_cutoff, + dim=self.dimension, + minlam=self.min_lam, + maxlam=self.max_lam, + ncycle=self.ncycle, + nstep=self.nstep, + stressfreq=self.stressfreq, ) return coordinates, {"final_stress": final_stress} @@ -185,9 +181,7 @@ def __init__(self, dimension=2, **kwargs): Number of dimensions to which the conformational space will be reduced to (default is 3). """ - self.pca = sklearn.decomposition.PCA( - n_components=dimension, **kwargs - ) + self.pca = sklearn.decomposition.PCA(n_components=dimension, **kwargs) def __call__(self, coordinates): """ diff --git a/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py b/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py index d1e05e1cd2..26315fdf40 100644 --- a/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py +++ b/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py @@ -187,9 +187,7 @@ def reduce_dimensionality( if distance_matrix: if not hasattr(distance_matrix, "__iter__"): distance_matrix = [distance_matrix] - if ensembles is not None and len(distance_matrix) != len( - merged_ensembles - ): + if ensembles is not None and len(distance_matrix) != len(merged_ensembles): raise ValueError( "Dimensions of provided list of distance matrices " "does not match that of provided list of " @@ -204,9 +202,7 @@ def reduce_dimensionality( distance_matrix = [] for merged_ensemble in merged_ensembles: distance_matrix.append( - get_distance_matrix( - merged_ensemble, select=select, **kwargs - ) + get_distance_matrix(merged_ensemble, select=select, **kwargs) ) args = [] @@ -215,14 +211,10 @@ def reduce_dimensionality( args += [(d,) for d in distance_matrix] else: for merged_ensemble in merged_ensembles: - coordinates = merged_ensemble.trajectory.timeseries( - order="fac" - ) + coordinates = merged_ensemble.trajectory.timeseries(order="fac") # Flatten coordinate matrix into n_frame x n_coordinates - coordinates = np.reshape( - coordinates, (coordinates.shape[0], -1) - ) + coordinates = np.reshape(coordinates, (coordinates.shape[0], -1)) args.append((coordinates,)) diff --git a/package/MDAnalysis/analysis/encore/similarity.py b/package/MDAnalysis/analysis/encore/similarity.py index 17b9fb2886..d1abbded74 100644 --- a/package/MDAnalysis/analysis/encore/similarity.py +++ b/package/MDAnalysis/analysis/encore/similarity.py @@ -302,15 +302,12 @@ def harmonic_ensemble_similarity(sigma1, sigma2, x1, x2): ) d_hes = 0.25 * ( - np.dot(np.transpose(d_avg), np.dot(sigma1_inv + sigma2_inv, d_avg)) - + trace + np.dot(np.transpose(d_avg), np.dot(sigma1_inv + sigma2_inv, d_avg)) + trace ) return d_hes -def clustering_ensemble_similarity( - cc, ens1, ens1_id, ens2, ens2_id, select="name CA" -): +def clustering_ensemble_similarity(cc, ens1, ens1_id, ens2, ens2_id, select="name CA"): """Clustering ensemble similarity: calculate the probability densities from the clusters and calculate discrete Jensen-Shannon divergence. @@ -591,19 +588,13 @@ def dimred_ensemble_similarity( ln_P1_exp_P1 = np.average(np.log(kde1.evaluate(resamples1))) ln_P2_exp_P2 = np.average(np.log(kde2.evaluate(resamples2))) ln_P1P2_exp_P1 = np.average( - np.log( - 0.5 * (kde1.evaluate(resamples1) + kde2.evaluate(resamples1)) - ) + np.log(0.5 * (kde1.evaluate(resamples1) + kde2.evaluate(resamples1))) ) ln_P1P2_exp_P2 = np.average( - np.log( - 0.5 * (kde1.evaluate(resamples2) + kde2.evaluate(resamples2)) - ) + np.log(0.5 * (kde1.evaluate(resamples2) + kde2.evaluate(resamples2))) ) - return 0.5 * ( - ln_P1_exp_P1 - ln_P1P2_exp_P1 + ln_P2_exp_P2 - ln_P1P2_exp_P2 - ) + return 0.5 * (ln_P1_exp_P1 - ln_P1P2_exp_P1 + ln_P2_exp_P2 - ln_P1P2_exp_P2) def cumulative_gen_kde_pdfs( @@ -690,9 +681,7 @@ def cumulative_gen_kde_pdfs( return (kdes, resamples, embedded_ensembles) -def write_output( - matrix, base_fname=None, header="", suffix="", extension="dat" -): +def write_output(matrix, base_fname=None, header="", suffix="", extension="dat"): """ Write output matrix with a nice format, to stdout and optionally a file. @@ -905,10 +894,7 @@ def hes( """ - if ( - not isinstance(weights, (list, tuple, np.ndarray)) - and weights == "mass" - ): + if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": weights = ["mass" for _ in range(len(ensembles))] elif weights is not None: if len(weights) != len(ensembles): @@ -957,9 +943,7 @@ def hes( ensembles_list = [] for i, ensemble in enumerate(ensembles): ensembles_list.append( - get_ensemble_bootstrap_samples( - ensemble, samples=bootstrapping_samples - ) + get_ensemble_bootstrap_samples(ensemble, samples=bootstrapping_samples) ) for t in range(bootstrapping_samples): logging.info("The coordinates will be bootstrapped.") @@ -1254,9 +1238,7 @@ def ces( failed_runs += 1 k += 1 continue - values[i].append( - np.zeros((len(ensembles[j]), len(ensembles[j]))) - ) + values[i].append(np.zeros((len(ensembles[j]), len(ensembles[j])))) for pair in pairs_indices: # Calculate dJS @@ -1467,16 +1449,10 @@ def dres( dimensionality_reduction_methods = [dimensionality_reduction_method] any_method_accept_distance_matrix = np.any( - [ - method.accepts_distance_matrix - for method in dimensionality_reduction_methods - ] + [method.accepts_distance_matrix for method in dimensionality_reduction_methods] ) all_methods_accept_distance_matrix = np.all( - [ - method.accepts_distance_matrix - for method in dimensionality_reduction_methods - ] + [method.accepts_distance_matrix for method in dimensionality_reduction_methods] ) # Register which ensembles the samples belong to @@ -1508,8 +1484,7 @@ def dres( ensembles = [] for j in range(bootstrapping_samples): ensembles.append( - ensembles_list[i, j] - for i in range(ensembles_list.shape[0]) + ensembles_list[i, j] for i in range(ensembles_list.shape[0]) ) else: # if all methods accept distances matrices, duplicate @@ -1540,9 +1515,7 @@ def dres( values[i] = [] for j in range(bootstrapping_samples): - values[i].append( - np.zeros((len(ensembles[j]), len(ensembles[j]))) - ) + values[i].append(np.zeros((len(ensembles[j]), len(ensembles[j])))) kdes, resamples, embedded_ensembles = gen_kde_pdfs( coordinates[k], diff --git a/package/MDAnalysis/analysis/encore/utils.py b/package/MDAnalysis/analysis/encore/utils.py index ae6407ddd1..77bc7a4189 100644 --- a/package/MDAnalysis/analysis/encore/utils.py +++ b/package/MDAnalysis/analysis/encore/utils.py @@ -128,9 +128,7 @@ def loadz(self, fname): raise TypeError self.metadata = loaded["metadata"] else: - if self.size * (self.size - 1) / 2 + self.size != len( - loaded["elements"] - ): + if self.size * (self.size - 1) / 2 + self.size != len(loaded["elements"]): raise TypeError self._elements = loaded["elements"] @@ -241,9 +239,7 @@ class description. if not hasattr(self.functions, "__iter__"): self.functions = [self.functions] * len(args) if len(self.functions) != len(args): - self.functions = self.functions[:] * ( - len(args) // len(self.functions) - ) + self.functions = self.functions[:] * (len(args) // len(self.functions)) # Arguments should be present if args is None: @@ -279,9 +275,7 @@ def worker(self, q, results): if i == "STOP": return - results.put( - (i, self.functions[i](*self.args[i], **self.kwargs[i])) - ) + results.put((i, self.functions[i](*self.args[i], **self.kwargs[i]))) def run(self): r""" diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index a767c5c578..93d10067a5 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -169,9 +169,7 @@ def neighbour_generator(positions, cutoff): n_x = len(grid) n_y = len(grid[0]) n_z = len(grid[0][0]) - for cell_x, cell_y, cell_z in itertools.product( - range(n_x), range(n_y), range(n_z) - ): + for cell_x, cell_y, cell_z in itertools.product(range(n_x), range(n_y), range(n_z)): atoms = grid[cell_x][cell_y][cell_z] # collect all atoms in own cell and neighboring cell all_atoms = [] @@ -281,15 +279,11 @@ def __init__( self._timesteps = None # time for each frame self.ReportVector = ReportVector self.Bonus_groups = ( - [self.u.select_atoms(item) for item in Bonus_groups] - if Bonus_groups - else [] + [self.u.select_atoms(item) for item in Bonus_groups] if Bonus_groups else [] ) self.ca = self.u.select_atoms(self.select) - def _generate_output( - self, w, v, outputobject, ReportVector=None, counter=0 - ): + def _generate_output(self, w, v, outputobject, ReportVector=None, counter=0): """Appends time, eigenvalues and eigenvectors to results. This generates the output by adding eigenvalue and @@ -476,9 +470,7 @@ def generate_kirchoff(self): ): iresidue = residue_index_map[i_atom] jresidue = residue_index_map[j_atom] - contact = ( - inv_sqrt_res_sizes[iresidue] * inv_sqrt_res_sizes[jresidue] - ) + contact = inv_sqrt_res_sizes[iresidue] * inv_sqrt_res_sizes[jresidue] matrix[iresidue][jresidue] -= contact matrix[jresidue][iresidue] -= contact matrix[iresidue][iresidue] += contact diff --git a/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py b/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py index 3f80affc81..dd85f35e0d 100644 --- a/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py +++ b/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py @@ -62,14 +62,12 @@ hbond_autocorrel.find_hydrogen_donors, release="2.0.0", remove="3.0.0", - message="The function was moved to " - "MDAnalysis.analysis.hbonds.hbond_autocorrel.", + message="The function was moved to " "MDAnalysis.analysis.hbonds.hbond_autocorrel.", ) HydrogenBondAutoCorrel = deprecate( hbond_autocorrel.HydrogenBondAutoCorrel, release="2.0.0", remove="3.0.0", - message="The class was moved to " - "MDAnalysis.analysis.hbonds.hbond_autocorrel.", + message="The class was moved to " "MDAnalysis.analysis.hbonds.hbond_autocorrel.", ) diff --git a/package/MDAnalysis/analysis/helix_analysis.py b/package/MDAnalysis/analysis/helix_analysis.py index e0edf76370..a8c48aa682 100644 --- a/package/MDAnalysis/analysis/helix_analysis.py +++ b/package/MDAnalysis/analysis/helix_analysis.py @@ -176,9 +176,7 @@ def local_screw_angles(global_axis, ref_axis, helix_directions): # angles from projection to perp refs = np.array([perp, ortho]) # (2, 3) - norms = _, ortho_norm = np.outer( - mdamath.pnorm(refs), mdamath.pnorm(proj_plane) - ) + norms = _, ortho_norm = np.outer(mdamath.pnorm(refs), mdamath.pnorm(proj_plane)) cos = cos_perp, cos_ortho = np.matmul(refs, proj_plane.T) / norms to_perp, to_ortho = np.arccos(np.clip(cos, -1, 1)) # (2, n_vec) to_ortho[ortho_norm == 0] = 0 # ? @@ -291,9 +289,7 @@ def helix_analysis(positions, ref_axis=(0, 0, 1)): origins[-1] -= radii[-1] * local_helix_directions[-1] helix_axes = vector_of_best_fit(origins) - screw = local_screw_angles( - helix_axes, np.asarray(ref_axis), local_helix_directions - ) + screw = local_screw_angles(helix_axes, np.asarray(ref_axis), local_helix_directions) results = { "local_twists": local_twists, @@ -401,9 +397,7 @@ def __init__( flatten_single_helix=True, split_residue_sequences=True, ): - super(HELANAL, self).__init__( - universe.universe.trajectory, verbose=verbose - ) + super(HELANAL, self).__init__(universe.universe.trajectory, verbose=verbose) selections = util.asiterable(select) atomgroups = [universe.select_atoms(s) for s in selections] consecutive = [] @@ -467,9 +461,7 @@ def _prepare(self): self.results[key] = empty self.results.global_axis = [self._zeros_per_frame((3,)) for n in n_res] - self.results.all_bends = [ - self._zeros_per_frame((n - 3, n - 3)) for n in n_res - ] + self.results.all_bends = [self._zeros_per_frame((n - 3, n - 3)) for n in n_res] def _single_frame(self): _f = self._frame_index @@ -484,9 +476,7 @@ def _conclude(self): self.results.global_tilts = tilts = [] norm_ref = (self.ref_axis**2).sum() ** 0.5 for axes in self.results.global_axis: - cos = np.matmul(self.ref_axis, axes.T) / ( - mdamath.pnorm(axes) * norm_ref - ) + cos = np.matmul(self.ref_axis, axes.T) / (mdamath.pnorm(axes) * norm_ref) cos = np.clip(cos, -1.0, 1.0) tilts.append(np.rad2deg(np.arccos(cos))) diff --git a/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py b/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py index 544bd6e4e1..04b4707d50 100644 --- a/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py +++ b/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py @@ -255,10 +255,12 @@ logger = logging.getLogger(__name__) -due.cite(Doi("10.1039/C9CP01532A"), - description="Hydrogen bond analysis implementation", - path="MDAnalysis.analysis.hydrogenbonds.hbond_analysis", - cite_module=True) +due.cite( + Doi("10.1039/C9CP01532A"), + description="Hydrogen bond analysis implementation", + path="MDAnalysis.analysis.hydrogenbonds.hbond_analysis", + cite_module=True, +) del Doi @@ -272,18 +274,29 @@ class HydrogenBondAnalysis(AnalysisBase): @classmethod def get_supported_backends(cls): - return ('serial', 'multiprocessing', 'dask',) + return ( + "serial", + "multiprocessing", + "dask", + ) - def __init__(self, universe, - donors_sel=None, hydrogens_sel=None, acceptors_sel=None, - between=None, d_h_cutoff=1.2, - d_a_cutoff=3.0, d_h_a_angle_cutoff=150, - update_selections=True): + def __init__( + self, + universe, + donors_sel=None, + hydrogens_sel=None, + acceptors_sel=None, + between=None, + d_h_cutoff=1.2, + d_a_cutoff=3.0, + d_h_a_angle_cutoff=150, + update_selections=True, + ): """Set up atom selections and geometric criteria for finding hydrogen bonds in a Universe. Hydrogen bond selections with `donors_sel` , `hydrogens_sel`, and - `acceptors_sel` may be achieved with either a *resname*, atom *name* + `acceptors_sel` may be achieved with either a *resname*, atom *name* combination, or when those are absent, with atom *type* selections. Parameters @@ -340,7 +353,7 @@ def __init__(self, universe, .. versionadded:: 2.0.0 Added `between` keyword .. versionchanged:: 2.4.0 - Added use of atom types in selection strings for hydrogen atoms, + Added use of atom types in selection strings for hydrogen atoms, bond donors, or bond acceptors .. versionchanged:: 2.8.0 Introduced :meth:`get_supported_backends` allowing for parallel execution on @@ -355,14 +368,19 @@ def __init__(self, universe, self._trajectory = self.u.trajectory self._donors_sel = donors_sel.strip() if donors_sel is not None else donors_sel - self._hydrogens_sel = hydrogens_sel.strip() if hydrogens_sel is not None else hydrogens_sel - self._acceptors_sel = acceptors_sel.strip() if acceptors_sel is not None else acceptors_sel - - msg = ("{} is an empty selection string - no hydrogen bonds will " - "be found. This may be intended, but please check your " - "selection." - ) - for sel in ['donors_sel', 'hydrogens_sel', 'acceptors_sel']: + self._hydrogens_sel = ( + hydrogens_sel.strip() if hydrogens_sel is not None else hydrogens_sel + ) + self._acceptors_sel = ( + acceptors_sel.strip() if acceptors_sel is not None else acceptors_sel + ) + + msg = ( + "{} is an empty selection string - no hydrogen bonds will " + "be found. This may be intended, but please check your " + "selection." + ) + for sel in ["donors_sel", "hydrogens_sel", "acceptors_sel"]: val = getattr(self, sel) if isinstance(val, str) and not val: warnings.warn(msg.format(sel)) @@ -380,7 +398,7 @@ def __init__(self, universe, between_ags.append( [ self.u.select_atoms(group1, updating=False), - self.u.select_atoms(group2, updating=False) + self.u.select_atoms(group2, updating=False), ] ) @@ -388,7 +406,6 @@ def __init__(self, universe, else: self.between_ags = None - self.d_h_cutoff = d_h_cutoff self.d_a_cutoff = d_a_cutoff self.d_h_a_angle = d_h_a_angle_cutoff @@ -403,23 +420,19 @@ def __init__(self, universe, self._hydrogens_sel = self.guess_hydrogens() # Select atom groups - self._acceptors = self.u.select_atoms(self.acceptors_sel, - updating=self.update_selections) + self._acceptors = self.u.select_atoms( + self.acceptors_sel, updating=self.update_selections + ) self._donors, self._hydrogens = self._get_dh_pairs() - def guess_hydrogens(self, - select='all', - max_mass=1.1, - min_charge=0.3, - min_mass=0.9 - ): + def guess_hydrogens(self, select="all", max_mass=1.1, min_charge=0.3, min_mass=0.9): """Guesses which hydrogen atoms should be used in the analysis. Parameters ---------- select: str (optional) - :ref:`Selection string ` for atom group - from which hydrogens will be identified. (e.g., ``(resname X and + :ref:`Selection string ` for atom group + from which hydrogens will be identified. (e.g., ``(resname X and name H1)`` or ``type 2``) max_mass: float (optional) The mass of a hydrogen atom must be less than this value. @@ -431,24 +444,24 @@ def guess_hydrogens(self, Returns ------- potential_hydrogens: str - String containing the :attr:`resname` and :attr:`name` of all + String containing the :attr:`resname` and :attr:`name` of all hydrogen atoms potentially capable of forming hydrogen bonds. Notes ----- - Hydrogen selections may be achieved with either a resname, atom + Hydrogen selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. This function makes use of atomic masses and atomic charges to identify - which atoms are hydrogen atoms that are capable of participating in - hydrogen bonding. If an atom has a mass less than :attr:`max_mass` and - an atomic charge greater than :attr:`min_charge` then it is considered + which atoms are hydrogen atoms that are capable of participating in + hydrogen bonding. If an atom has a mass less than :attr:`max_mass` and + an atomic charge greater than :attr:`min_charge` then it is considered capable of participating in hydrogen bonds. - If :attr:`hydrogens_sel` is `None`, this function is called to guess + If :attr:`hydrogens_sel` is `None`, this function is called to guess the selection. - Alternatively, this function may be used to quickly generate a + Alternatively, this function may be used to quickly generate a :class:`str` of potential hydrogen atoms involved in hydrogen bonding. This str may then be modified before being used to set the attribute :attr:`hydrogens_sel`. @@ -464,25 +477,27 @@ def guess_hydrogens(self, ag = self.u.select_atoms(select) hydrogens_ag = ag[ - np.logical_and.reduce(( - ag.masses < max_mass, - ag.charges > min_charge, - ag.masses > min_mass, - )) + np.logical_and.reduce( + ( + ag.masses < max_mass, + ag.charges > min_charge, + ag.masses > min_mass, + ) + ) ] return self._group_categories(hydrogens_ag) - def guess_donors(self, select='all', max_charge=-0.5): + def guess_donors(self, select="all", max_charge=-0.5): """Guesses which atoms could be considered donors in the analysis. Only - use if the universe topology does not contain bonding information, + use if the universe topology does not contain bonding information, otherwise donor-hydrogen pairs may be incorrectly assigned. Parameters ---------- select: str (optional) - :ref:`Selection string ` for atom group - from which donors will be identified. (e.g., ``(resname X and name + :ref:`Selection string ` for atom group + from which donors will be identified. (e.g., ``(resname X and name O1)`` or ``type 2``) max_charge: float (optional) The charge of a donor atom must be less than this value. @@ -490,27 +505,27 @@ def guess_donors(self, select='all', max_charge=-0.5): Returns ------- potential_donors: str - String containing the :attr:`resname` and :attr:`name` of all atoms + String containing the :attr:`resname` and :attr:`name` of all atoms that are potentially capable of forming hydrogen bonds. Notes ----- - Donor selections may be achieved with either a resname, atom + Donor selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. - This function makes use of and atomic charges to identify which atoms - could be considered donor atoms in the hydrogen bond analysis. If an - atom has an atomic charge less than :attr:`max_charge`, and it is - within :attr:`d_h_cutoff` of a hydrogen atom, then it is considered + This function makes use of and atomic charges to identify which atoms + could be considered donor atoms in the hydrogen bond analysis. If an + atom has an atomic charge less than :attr:`max_charge`, and it is + within :attr:`d_h_cutoff` of a hydrogen atom, then it is considered capable of participating in hydrogen bonds. - If :attr:`donors_sel` is `None`, and the universe topology does not - have bonding information, this function is called to guess the + If :attr:`donors_sel` is `None`, and the universe topology does not + have bonding information, this function is called to guess the selection. - Alternatively, this function may be used to quickly generate a - :class:`str` of potential donor atoms involved in hydrogen bonding. - This :class:`str` may then be modified before being used to set the + Alternatively, this function may be used to quickly generate a + :class:`str` of potential donor atoms involved in hydrogen bonding. + This :class:`str` may then be modified before being used to set the attribute :attr:`donors_sel`. @@ -520,7 +535,7 @@ def guess_donors(self, select='all', max_charge=-0.5): """ # We need to know `hydrogens_sel` before we can find donors - # Use a new variable `hydrogens_sel` so that we do not set + # Use a new variable `hydrogens_sel` so that we do not set # `self.hydrogens_sel` if it is currently `None` if self.hydrogens_sel is None: hydrogens_sel = self.guess_hydrogens() @@ -532,8 +547,10 @@ def guess_donors(self, select='all', max_charge=-0.5): # times faster to access. This is because u.bonds also calculates # properties of each bond (e.g bond length). See: # https://github.com/MDAnalysis/mdanalysis/issues/2396#issuecomment-596251787 - if (hasattr(self.u._topology, 'bonds') - and len(self.u._topology.bonds.values) != 0): + if ( + hasattr(self.u._topology, "bonds") + and len(self.u._topology.bonds.values) != 0 + ): donors_ag = find_hydrogen_donors(hydrogens_ag) donors_ag = donors_ag.intersection(self.u.select_atoms(select)) else: @@ -541,7 +558,7 @@ def guess_donors(self, select='all', max_charge=-0.5): "({donors_sel}) and around {d_h_cutoff} {hydrogens_sel}".format( donors_sel=select, d_h_cutoff=self.d_h_cutoff, - hydrogens_sel=hydrogens_sel + hydrogens_sel=hydrogens_sel, ) ) @@ -549,17 +566,17 @@ def guess_donors(self, select='all', max_charge=-0.5): return self._group_categories(donors_ag) - def guess_acceptors(self, select='all', max_charge=-0.5): + def guess_acceptors(self, select="all", max_charge=-0.5): """Guesses which atoms could be considered acceptors in the analysis. - Acceptor selections may be achieved with either a resname, atom + Acceptor selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. Parameters ---------- select: str (optional) :ref:`Selection string ` for atom group - from which acceptors will be identified. (e.g., ``(resname X and + from which acceptors will be identified. (e.g., ``(resname X and name O1)`` or ``type 2``) max_charge: float (optional) The charge of an acceptor atom must be less than this value. @@ -567,25 +584,25 @@ def guess_acceptors(self, select='all', max_charge=-0.5): Returns ------- potential_acceptors: str - String containing the :attr:`resname` and :attr:`name` of all atoms + String containing the :attr:`resname` and :attr:`name` of all atoms that potentially capable of forming hydrogen bonds. Notes ----- - Acceptor selections may be achieved with either a resname, atom + Acceptor selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. - This function makes use of and atomic charges to identify which atoms - could be considered acceptor atoms in the hydrogen bond analysis. If - an atom has an atomic charge less than :attr:`max_charge` then it is + This function makes use of and atomic charges to identify which atoms + could be considered acceptor atoms in the hydrogen bond analysis. If + an atom has an atomic charge less than :attr:`max_charge` then it is considered capable of participating in hydrogen bonds. - If :attr:`acceptors_sel` is `None`, this function is called to guess + If :attr:`acceptors_sel` is `None`, this function is called to guess the selection. - Alternatively, this function may be used to quickly generate a - :class:`str` of potential acceptor atoms involved in hydrogen bonding. - This :class:`str` may then be modified before being used to set the + Alternatively, this function may be used to quickly generate a + :class:`str` of potential acceptor atoms involved in hydrogen bonding. + This :class:`str` may then be modified before being used to set the attribute :attr:`acceptors_sel`. @@ -601,14 +618,14 @@ def guess_acceptors(self, select='all', max_charge=-0.5): @staticmethod def _group_categories(group): - """ Find categories according to universe constraints - + """Find categories according to universe constraints + Parameters ---------- group : AtomGroup - AtomGroups corresponding to either hydrogen bond acceptors, + AtomGroups corresponding to either hydrogen bond acceptors, donors, or hydrogen atoms that meet their respective charge - and mass constraints. + and mass constraints. Returns ------- @@ -621,16 +638,14 @@ def _group_categories(group): """ if hasattr(group, "resnames") and hasattr(group, "names"): - group_list = np.unique([ - '(resname {} and name {})'.format(r, - p) for r, p in zip(group.resnames, group.names) - ]) - else: group_list = np.unique( [ - 'type {}'.format(tp) for tp in group.types + "(resname {} and name {})".format(r, p) + for r, p in zip(group.resnames, group.names) ] ) + else: + group_list = np.unique(["type {}".format(tp) for tp in group.types]) return " or ".join(group_list) @@ -640,7 +655,7 @@ def _get_dh_pairs(self): Returns ------- donors, hydrogens: AtomGroup, AtomGroup - AtomGroups corresponding to all donors and all hydrogens. + AtomGroups corresponding to all donors and all hydrogens. AtomGroups are ordered such that, if zipped, will produce a list of donor-hydrogen pairs. """ @@ -651,15 +666,23 @@ def _get_dh_pairs(self): # We're using u._topology.bonds rather than u.bonds as it is a million times faster to access. # This is because u.bonds also calculates properties of each bond (e.g bond length). # See https://github.com/MDAnalysis/mdanalysis/issues/2396#issuecomment-596251787 - if not (hasattr(self.u._topology, 'bonds') and len(self.u._topology.bonds.values) != 0): - raise NoDataError('Cannot assign donor-hydrogen pairs via topology as no bond information is present. ' - 'Please either: load a topology file with bond information; use the guess_bonds() ' - 'topology guesser; or set HydrogenBondAnalysis.donors_sel so that a distance cutoff ' - 'can be used.') + if not ( + hasattr(self.u._topology, "bonds") + and len(self.u._topology.bonds.values) != 0 + ): + raise NoDataError( + "Cannot assign donor-hydrogen pairs via topology as no bond information is present. " + "Please either: load a topology file with bond information; use the guess_bonds() " + "topology guesser; or set HydrogenBondAnalysis.donors_sel so that a distance cutoff " + "can be used." + ) hydrogens = self.u.select_atoms(self.hydrogens_sel) - donors = sum(h.bonded_atoms[0] for h in hydrogens) if hydrogens \ + donors = ( + sum(h.bonded_atoms[0] for h in hydrogens) + if hydrogens else AtomGroup([], self.u) + ) # Otherwise, use d_h_cutoff as a cutoff distance else: @@ -671,7 +694,7 @@ def _get_dh_pairs(self): hydrogens.positions, max_cutoff=self.d_h_cutoff, box=self.u.dimensions, - return_distances=False + return_distances=False, ).T donors = donors[donors_indices] @@ -682,20 +705,20 @@ def _get_dh_pairs(self): def _filter_atoms(self, donors, acceptors): """Create a mask to filter donor, hydrogen and acceptor atoms. - This can be used to consider only hydrogen bonds between two or more - specified groups. + This can be used to consider only hydrogen bonds between two or more + specified groups. - Groups are specified with the `between` keyword when creating the - HydrogenBondAnalysis object. + Groups are specified with the `between` keyword when creating the + HydrogenBondAnalysis object. - Returns - ------- - mask: np.ndarray + Returns + ------- + mask: np.ndarray - .. versionchanged:: 2.5.0 - Change return value to a mask instead of separate AtomGroups. -`` + .. versionchanged:: 2.5.0 + Change return value to a mask instead of separate AtomGroups. + `` """ mask = np.full(donors.n_atoms, fill_value=False) @@ -703,27 +726,25 @@ def _filter_atoms(self, donors, acceptors): # Find donors in G1 and acceptors in G2 mask[ - np.logical_and( - np.isin(donors.indices, group1.indices), - np.isin(acceptors.indices, group2.indices) - ) + np.logical_and( + np.isin(donors.indices, group1.indices), + np.isin(acceptors.indices, group2.indices), + ) ] = True # Find acceptors in G1 and donors in G2 mask[ np.logical_and( np.isin(acceptors.indices, group1.indices), - np.isin(donors.indices, group2.indices) + np.isin(donors.indices, group2.indices), ) ] = True return mask - def _prepare(self): self.results.hbonds = [[], [], [], [], [], []] - def _single_frame(self): box = self._ts.dimensions @@ -770,7 +791,7 @@ def _single_frame(self): tmp_donors.positions, tmp_hydrogens.positions, tmp_acceptors.positions, - box=box + box=box, ) ) hbond_indices = np.where(d_h_a_angles > self.d_h_a_angle)[0] @@ -790,8 +811,7 @@ def _single_frame(self): hbond_angles = d_h_a_angles[hbond_indices] # Store data on hydrogen bonds found at this frame - self.results.hbonds[0].extend(np.full_like(hbond_donors, - self._ts.frame)) + self.results.hbonds[0].extend(np.full_like(hbond_donors, self._ts.frame)) self.results.hbonds[1].extend(hbond_donors.indices) self.results.hbonds[2].extend(hbond_hydrogens.indices) self.results.hbonds[3].extend(hbond_acceptors.indices) @@ -803,13 +823,15 @@ def _conclude(self): self.results.hbonds = np.asarray(self.results.hbonds).T def _get_aggregator(self): - return ResultsGroup(lookup={'hbonds': ResultsGroup.ndarray_hstack}) + return ResultsGroup(lookup={"hbonds": ResultsGroup.ndarray_hstack}) @property def hbonds(self): - wmsg = ("The `hbonds` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.hbonds` instead.") + wmsg = ( + "The `hbonds` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.hbonds` instead." + ) warnings.warn(wmsg, DeprecationWarning) return self.results.hbonds @@ -864,8 +886,7 @@ def lifetime(self, tau_max=20, window_step=1, intermittency=0): "before the hydrogen bonds are found" ) logger.error( - "Autocorrelation: Please use the .run() before calling this" - "function" + "Autocorrelation: Please use the .run() before calling this" "function" ) raise NoDataError(".hbonds attribute is None: use .run() first") @@ -890,13 +911,10 @@ def lifetime(self, tau_max=20, window_step=1, intermittency=0): found_hydrogen_bonds[frame_index].add(frozenset(hbond[2:4])) intermittent_hbonds = correct_intermittency( - found_hydrogen_bonds, - intermittency=intermittency + found_hydrogen_bonds, intermittency=intermittency ) tau_timeseries, timeseries, timeseries_data = autocorrelation( - intermittent_hbonds, - tau_max, - window_step=window_step + intermittent_hbonds, tau_max, window_step=window_step ) return np.vstack([tau_timeseries, timeseries]) @@ -912,8 +930,9 @@ def count_by_time(self): the number of hydrogen bonds over time. """ - indices, tmp_counts = np.unique(self.results.hbonds[:, 0], axis=0, - return_counts=True) + indices, tmp_counts = np.unique( + self.results.hbonds[:, 0], axis=0, return_counts=True + ) indices -= self.start indices /= self.step @@ -929,13 +948,13 @@ def count_by_type(self): Returns ------- counts : numpy.ndarray - Each row of the array contains the donor resname, donor atom type, - acceptor resname, acceptor atom type and the total number of times + Each row of the array contains the donor resname, donor atom type, + acceptor resname, acceptor atom type and the total number of times the hydrogen bond was found. Note ---- - Unique hydrogen bonds are determined through a consideration of the + Unique hydrogen bonds are determined through a consideration of the resname and atom type of the donor and acceptor atoms in a hydrogen bond. """ @@ -950,12 +969,12 @@ def count_by_type(self): a_res = len(a.types) * ["None"] tmp_hbonds = np.array([d_res, d.types, a_res, a.types], dtype=str).T - hbond_type, type_counts = np.unique( - tmp_hbonds, axis=0, return_counts=True) + hbond_type, type_counts = np.unique(tmp_hbonds, axis=0, return_counts=True) hbond_type_list = [] for hb_type, hb_count in zip(hbond_type, type_counts): - hbond_type_list.append([":".join(hb_type[:2]), - ":".join(hb_type[2:4]), hb_count]) + hbond_type_list.append( + [":".join(hb_type[:2]), ":".join(hb_type[2:4]), hb_count] + ) return np.array(hbond_type_list) @@ -979,12 +998,10 @@ def count_by_ids(self): a = self.u.atoms[self.results.hbonds[:, 3].astype(np.intp)] tmp_hbonds = np.array([d.ids, h.ids, a.ids]).T - hbond_ids, ids_counts = np.unique(tmp_hbonds, axis=0, - return_counts=True) + hbond_ids, ids_counts = np.unique(tmp_hbonds, axis=0, return_counts=True) # Find unique hbonds and sort rows so that most frequent observed bonds are at the top of the array - unique_hbonds = np.concatenate((hbond_ids, ids_counts[:, None]), - axis=1) + unique_hbonds = np.concatenate((hbond_ids, ids_counts[:, None]), axis=1) unique_hbonds = unique_hbonds[unique_hbonds[:, 3].argsort()[::-1]] return unique_hbonds @@ -992,7 +1009,7 @@ def count_by_ids(self): @property def donors_sel(self): """Selection string for the hydrogen bond donor atoms. - + .. versionadded:: 2.10.0 """ return self._donors_sel @@ -1005,7 +1022,7 @@ def donors_sel(self, value): @property def hydrogens_sel(self): """Selection string for the hydrogen bond hydrogen atoms. - + .. versionadded:: 2.10.0 """ return self._hydrogens_sel @@ -1020,7 +1037,7 @@ def hydrogens_sel(self, value): @property def acceptors_sel(self): """Selection string for the hydrogen bond acceptor atoms. - + .. versionadded:: 2.10.0 """ return self._acceptors_sel @@ -1030,5 +1047,6 @@ def acceptors_sel(self, value): self._acceptors_sel = value if self._acceptors_sel is None: self._acceptors_sel = self.guess_acceptors() - self._acceptors = self.u.select_atoms(self._acceptors_sel, - updating=self.update_selections) \ No newline at end of file + self._acceptors = self.u.select_atoms( + self._acceptors_sel, updating=self.update_selections + ) diff --git a/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py b/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py index 749fe3533c..19198e4f69 100644 --- a/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py +++ b/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py @@ -328,20 +328,16 @@ def __init__( if exclusions is not None: if len(exclusions[0]) != len(exclusions[1]): - raise ValueError( - "'exclusion' must be two arrays of identical length" - ) - self.exclusions = np.column_stack( - (exclusions[0], exclusions[1]) - ).astype(np.intp) + raise ValueError("'exclusion' must be two arrays of identical length") + self.exclusions = np.column_stack((exclusions[0], exclusions[1])).astype( + np.intp + ) else: self.exclusions = None self.bond_type = bond_type if self.bond_type not in ["continuous", "intermittent"]: - raise ValueError( - "bond_type must be either 'continuous' or 'intermittent'" - ) + raise ValueError("bond_type must be either 'continuous' or 'intermittent'") self.a_crit = np.deg2rad(angle_crit) self.d_crit = dist_crit @@ -371,9 +367,7 @@ def _slice_traj(self, sample_time): if req_frames > n_frames: warnings.warn( "Number of required frames ({}) greater than the" - " number of frames in trajectory ({})".format( - req_frames, n_frames - ), + " number of frames in trajectory ({})".format(req_frames, n_frames), RuntimeWarning, ) @@ -477,9 +471,7 @@ def _single_run(self, start, stop): aidx = aidx[idx2] nbonds = len(hidx) # number of hbonds at t=0 - results = np.zeros_like( - np.arange(start, stop, self._skip), dtype=np.float32 - ) + results = np.zeros_like(np.arange(start, stop, self._skip), dtype=np.float32) if self.time_cut: # counter for time criteria @@ -488,9 +480,7 @@ def _single_run(self, start, stop): for i, ts in enumerate(self.u.trajectory[start : stop : self._skip]): box = self.u.dimensions if self.pbc else None - d = calc_bonds( - self.h.positions[hidx], self.a.positions[aidx], box=box - ) + d = calc_bonds(self.h.positions[hidx], self.a.positions[aidx], box=box) a = calc_angles( self.d.positions[hidx], self.h.positions[hidx], @@ -615,9 +605,7 @@ def triple(x, A1, A2, tau1, tau2, tau3): """Sum of three exponential functions""" A3 = 1 - (A1 + A2) return ( - A1 * np.exp(-x / tau1) - + A2 * np.exp(-x / tau2) - + A3 * np.exp(-x / tau3) + A1 * np.exp(-x / tau1) + A2 * np.exp(-x / tau2) + A3 * np.exp(-x / tau3) ) if self.bond_type == "continuous": @@ -658,9 +646,7 @@ def triple(x, A1, A2, tau1, tau2, tau3): self.solution["ier"] = ier if ier in [1, 2, 3, 4]: # solution found if ier is one of these values - self.solution["estimate"] = self._my_solve( - self.solution["time"], *p - ) + self.solution["estimate"] = self._my_solve(self.solution["time"], *p) else: warnings.warn("Solution to results not found", RuntimeWarning) diff --git a/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py b/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py index 027c0b7125..776e020b83 100644 --- a/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py +++ b/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py @@ -789,9 +789,7 @@ class WaterBridgeAnalysis(AnalysisBase): "OH", } ), - "GLYCAM06": tuple( - {"N", "NT", "O", "O2", "OH", "OS", "OW", "OY", "SM"} - ), + "GLYCAM06": tuple({"N", "NT", "O", "O2", "OH", "OS", "OW", "OY", "SM"}), "other": tuple(set([])), } @@ -959,9 +957,7 @@ def __init__( """ - super(WaterBridgeAnalysis, self).__init__( - universe.trajectory, **kwargs - ) + super(WaterBridgeAnalysis, self).__init__(universe.trajectory, **kwargs) self.water_selection = water_selection self.update_water_selection = update_water_selection # per-frame debugging output? @@ -1001,9 +997,7 @@ def __init__( acceptors = () self.forcefield = forcefield self.donors = tuple(set(self.DEFAULT_DONORS[forcefield]).union(donors)) - self.acceptors = tuple( - set(self.DEFAULT_ACCEPTORS[forcefield]).union(acceptors) - ) + self.acceptors = tuple(set(self.DEFAULT_ACCEPTORS[forcefield]).union(acceptors)) if self.selection1_type not in ("both", "donor", "acceptor"): raise ValueError( @@ -1092,15 +1086,11 @@ def _update_selection(self): "Size of selection 1 before filtering:" " {} atoms".format(len(self._s1)) ) - ns_selection_1 = AtomNeighborSearch( - self.u.atoms[self._s1], box=self.box - ) + ns_selection_1 = AtomNeighborSearch(self.u.atoms[self._s1], box=self.box) self._s1 = ns_selection_1.search( self.u.atoms[self._s2], self.selection_distance ).ix - self.logger_debug( - "Size of selection 1: {0} atoms".format(len(self._s1)) - ) + self.logger_debug("Size of selection 1: {0} atoms".format(len(self._s1))) if len(self._s1) == 0: logger.warning( @@ -1115,15 +1105,11 @@ def _update_selection(self): "Size of selection 2 before filtering:" " {} atoms".format(len(self._s2)) ) - ns_selection_2 = AtomNeighborSearch( - self.u.atoms[self._s2], box=self.box - ) + ns_selection_2 = AtomNeighborSearch(self.u.atoms[self._s2], box=self.box) self._s2 = ns_selection_2.search( self.u.atoms[self._s1], self.selection_distance ).ix - self.logger_debug( - "Size of selection 2: {0} atoms".format(len(self._s2)) - ) + self.logger_debug("Size of selection 2: {0} atoms".format(len(self._s2))) if len(self._s2) == 0: logger.warning( @@ -1140,16 +1126,10 @@ def _update_selection(self): .ix ) for atom_ix in self._s1_donors: - self._update_donor_h( - atom_ix, self._s1_h_donors, self._s1_donors_h - ) + self._update_donor_h(atom_ix, self._s1_h_donors, self._s1_donors_h) + self.logger_debug("Selection 1 donors: {0}".format(len(self._s1_donors))) self.logger_debug( - "Selection 1 donors: {0}".format(len(self._s1_donors)) - ) - self.logger_debug( - "Selection 1 donor hydrogens: {0}".format( - len(self._s1_h_donors) - ) + "Selection 1 donor hydrogens: {0}".format(len(self._s1_h_donors)) ) if self.selection1_type in ("acceptor", "both"): self._s1_acceptors = ( @@ -1179,16 +1159,10 @@ def _update_selection(self): .ix ) for atom_ix in self._s2_donors: - self._update_donor_h( - atom_ix, self._s2_h_donors, self._s2_donors_h - ) + self._update_donor_h(atom_ix, self._s2_h_donors, self._s2_donors_h) + self.logger_debug("Selection 2 donors: {0:d}".format(len(self._s2_donors))) self.logger_debug( - "Selection 2 donors: {0:d}".format(len(self._s2_donors)) - ) - self.logger_debug( - "Selection 2 donor hydrogens: {0:d}".format( - len(self._s2_h_donors) - ) + "Selection 2 donor hydrogens: {0:d}".format(len(self._s2_h_donors)) ) def _update_water_selection(self): @@ -1213,9 +1187,7 @@ def _update_water_selection(self): .ix ) - self.logger_debug( - "Size of water selection: {0} atoms".format(len(self._water)) - ) + self.logger_debug("Size of water selection: {0} atoms".format(len(self._water))) if len(self._water) == 0: logger.warning( @@ -1233,9 +1205,7 @@ def _update_water_selection(self): self._update_donor_h( atom_ix, self._water_h_donors, self._water_donors_h ) - self.logger_debug( - "Water donors: {0}".format(len(self._water_donors)) - ) + self.logger_debug("Water donors: {0}".format(len(self._water_donors))) self.logger_debug( "Water donor hydrogens: {0}".format(len(self._water_h_donors)) ) @@ -1244,9 +1214,7 @@ def _update_water_selection(self): .select_atoms("name {0}".format(" ".join(self.acceptors))) .ix ) - self.logger_debug( - "Water acceptors: {0}".format(len(self._water_acceptors)) - ) + self.logger_debug("Water acceptors: {0}".format(len(self._water_acceptors))) def _get_bonded_hydrogens(self, atom): """Find hydrogens bonded within cutoff to `atom`. @@ -1305,18 +1273,14 @@ def _prepare(self): if len(self._s1) and len(self._s2): self._update_water_selection() else: - logger.info( - "WaterBridgeAnalysis: " "no atoms found in the selection." - ) + logger.info("WaterBridgeAnalysis: " "no atoms found in the selection.") logger.info("WaterBridgeAnalysis: initial checks passed.") logger.info("WaterBridgeAnalysis: starting") logger.debug("WaterBridgeAnalysis: donors %r", self.donors) logger.debug("WaterBridgeAnalysis: acceptors %r", self.acceptors) - logger.debug( - "WaterBridgeAnalysis: water bridge %r", self.water_selection - ) + logger.debug("WaterBridgeAnalysis: water bridge %r", self.water_selection) if self.debug: logger.debug("Toggling debug to %r", self.debug) @@ -1430,9 +1394,7 @@ def _single_frame(self): angle, ) = line water_pool[(a_resname, a_resid)] = None - selection_1.append( - (h_index, d_index, a_index, None, dist, angle) - ) + selection_1.append((h_index, d_index, a_index, None, dist, angle)) selection_2.append((a_resname, a_resid)) if self.order > 0: self.logger_debug("Selection 1 Donors <-> Water Acceptors") @@ -1449,9 +1411,7 @@ def _single_frame(self): dist, angle, ) = line - selection_1.append( - (h_index, d_index, a_index, None, dist, angle) - ) + selection_1.append((h_index, d_index, a_index, None, dist, angle)) self.logger_debug("Water Donors <-> Selection 2 Acceptors") results = self._donor2acceptor( @@ -1490,9 +1450,7 @@ def _single_frame(self): angle, ) = line water_pool[(h_resname, h_resid)] = None - selection_1.append( - (a_index, None, h_index, d_index, dist, angle) - ) + selection_1.append((a_index, None, h_index, d_index, dist, angle)) selection_2.append((h_resname, h_resid)) if self.order > 0: @@ -1531,9 +1489,7 @@ def _single_frame(self): dist, angle, ) = line - selection_1.append( - (a_index, None, h_index, d_index, dist, angle) - ) + selection_1.append((a_index, None, h_index, d_index, dist, angle)) if self.order > 1: self.logger_debug("Water donor <-> Water Acceptors") @@ -1610,9 +1566,9 @@ def traverse_water_network(graph, node, end, route, maxdepth, result): for new_node in graph[node]: new_route = route[:] new_route.append(new_node) - new_node = self._expand_timeseries( - new_node, "sele1_sele2" - )[3][:2] + new_node = self._expand_timeseries(new_node, "sele1_sele2")[3][ + :2 + ] traverse_water_network( graph, new_node, end, new_route, maxdepth, result ) @@ -1736,8 +1692,7 @@ def _expand_timeseries(self, entry, output_format=None): atom1, atom2 = atom1, atom2 else: raise KeyError( - "Only 'sele1_sele2' or 'donor_acceptor' are allowed as output " - "format" + "Only 'sele1_sele2' or 'donor_acceptor' are allowed as output " "format" ) return ( @@ -1787,10 +1742,7 @@ def analysis(current, output, *args, **kwargs): link_func=self._compact_link, ) timeseries.append( - [ - self._expand_timeseries(entry, output_format) - for entry in new_frame - ] + [self._expand_timeseries(entry, output_format) for entry in new_frame] ) return timeseries @@ -1837,12 +1789,12 @@ def _count_by_type_analysis(self, current, output, *args, **kwargs): :return: """ - s1_index, to_index, s1, to_residue, dist, angle = ( - self._expand_timeseries(current[0]) + s1_index, to_index, s1, to_residue, dist, angle = self._expand_timeseries( + current[0] ) s1_resname, s1_resid, s1_name = s1 - from_index, s2_index, from_residue, s2, dist, angle = ( - self._expand_timeseries(current[-1]) + from_index, s2_index, from_residue, s2, dist, angle = self._expand_timeseries( + current[-1] ) s2_resname, s2_resid, s2_name = s2 key = ( @@ -1908,20 +1860,18 @@ def count_by_type(self, analysis_func=None, **kwargs): for i, key in enumerate(result_dict) ] else: - result = [ - (key, result_dict[key] / length) for key in result_dict - ] + result = [(key, result_dict[key] / length) for key in result_dict] return result else: return None def _count_by_time_analysis(self, current, output, *args, **kwargs): - s1_index, to_index, s1, to_residue, dist, angle = ( - self._expand_timeseries(current[0]) + s1_index, to_index, s1, to_residue, dist, angle = self._expand_timeseries( + current[0] ) s1_resname, s1_resid, s1_name = s1 - from_index, s2_index, from_residue, s2, dist, angle = ( - self._expand_timeseries(current[-1]) + from_index, s2_index, from_residue, s2, dist, angle = self._expand_timeseries( + current[-1] ) s2_resname, s2_resid, s2_name = s2 key = ( @@ -1963,20 +1913,18 @@ def count_by_time(self, analysis_func=None, **kwargs): link_func=self._full_link, **kwargs, ) - result.append( - (time, sum([result_dict[key] for key in result_dict])) - ) + result.append((time, sum([result_dict[key] for key in result_dict]))) return result else: return None def _timesteps_by_type_analysis(self, current, output, *args, **kwargs): - s1_index, to_index, s1, to_residue, dist, angle = ( - self._expand_timeseries(current[0]) + s1_index, to_index, s1, to_residue, dist, angle = self._expand_timeseries( + current[0] ) s1_resname, s1_resid, s1_name = s1 - from_index, s2_index, from_residue, s2, dist, angle = ( - self._expand_timeseries(current[-1]) + from_index, s2_index, from_residue, s2, dist, angle = self._expand_timeseries( + current[-1] ) s2_resname, s2_resid, s2_name = s2 key = ( @@ -2075,10 +2023,7 @@ def generate_table(self, output_format=None): logger.warning(msg) return None - if ( - self.results.timeseries is not None - and output_format == self.output_format - ): + if self.results.timeseries is not None and output_format == self.output_format: timeseries = self.results.timeseries else: # Recompute timeseries with correct output format @@ -2137,9 +2082,7 @@ def generate_table(self, output_format=None): + (distance, angle) ) cursor += 1 - assert ( - cursor == num_records - ), "Internal Error: Not all wb records stored" + assert cursor == num_records, "Internal Error: Not all wb records stored" table = out.view(np.rec.recarray) logger.debug( "WBridge: Stored results as table with %(num_records)d entries.", diff --git a/package/MDAnalysis/analysis/leaflet.py b/package/MDAnalysis/analysis/leaflet.py index 9ba5de87e7..9c735716d9 100644 --- a/package/MDAnalysis/analysis/leaflet.py +++ b/package/MDAnalysis/analysis/leaflet.py @@ -249,10 +249,7 @@ def update(self, cutoff=None): def sizes(self): """Dict of component index with size of component.""" return dict( - ( - (idx, len(component)) - for idx, component in enumerate(self.components) - ) + ((idx, len(component)) for idx, component in enumerate(self.components)) ) def groups(self, component_index=None): diff --git a/package/MDAnalysis/analysis/legacy/x3dna.py b/package/MDAnalysis/analysis/legacy/x3dna.py index 2365c18113..ba57edc263 100644 --- a/package/MDAnalysis/analysis/legacy/x3dna.py +++ b/package/MDAnalysis/analysis/legacy/x3dna.py @@ -330,9 +330,7 @@ def save(self, filename="x3dna.pickle"): """ import cPickle - cPickle.dump( - self.profiles, open(filename, "wb"), cPickle.HIGHEST_PROTOCOL - ) + cPickle.dump(self.profiles, open(filename, "wb"), cPickle.HIGHEST_PROTOCOL) def mean_std(self): """Returns the mean and standard deviation of base parameters. @@ -673,9 +671,7 @@ def __init__(self, filename, **kwargs): self.x3dna_param = kwargs.pop("x3dna_param", True) self.exe["xdna_ensemble"] = which(x3dna_exe_name) if self.exe["xdna_ensemble"] is None: - errmsg = "X3DNA binary {x3dna_exe_name!r} not found.".format( - **vars() - ) + errmsg = "X3DNA binary {x3dna_exe_name!r} not found.".format(**vars()) logger.fatal(errmsg) logger.fatal( "%(x3dna_exe_name)r must be on the PATH or provided as keyword argument 'executable'.", @@ -719,9 +715,7 @@ def run(self, **kwargs): f.write(inp) logger.debug("Wrote X3DNA input file %r for inspection", inpname) - logger.info( - "Starting X3DNA on %(filename)r (trajectory: %(dcd)r)", x3dnaargs - ) + logger.info("Starting X3DNA on %(filename)r (trajectory: %(dcd)r)", x3dnaargs) logger.debug("%s", self.exe["xdna_ensemble"]) with open(outname, "w") as output: x3dna = subprocess.call([inp], shell=True) @@ -772,20 +766,18 @@ def collect(self, **kwargs): outdir = kwargs.pop("outdir", os.path.curdir) logger.info("Collecting X3DNA profiles for run with id %s", run) - length = 1 # length of trajectory --- is this really needed?? No... just for info + length = ( + 1 # length of trajectory --- is this really needed?? No... just for info + ) if "*" in self.filename: import glob filenames = glob.glob(self.filename) length = len(filenames) if length == 0: - logger.error( - "Glob pattern %r did not find any files.", self.filename - ) + logger.error("Glob pattern %r did not find any files.", self.filename) raise ValueError( - "Glob pattern {0!r} did not find any files.".format( - self.filename - ) + "Glob pattern {0!r} did not find any files.".format(self.filename) ) logger.info( "Found %d input files based on glob pattern %s", @@ -842,9 +834,7 @@ def collect(self, **kwargs): run, line.strip(), ) - logger.exception( - "Check input file %r.", x3dna_output - ) + logger.exception("Check input file %r.", x3dna_output) raise records.append( [ @@ -894,9 +884,7 @@ def collect(self, **kwargs): run, line.strip(), ) - logger.exception( - "Check input file %r.", x3dna_output - ) + logger.exception("Check input file %r.", x3dna_output) raise records.append( [ @@ -941,9 +929,7 @@ def collect(self, **kwargs): os.makedirs(rundir) frame_x3dna_txt = os.path.join( rundir, - "bp_step_{0!s}_{1:04d}.dat.gz".format( - run, x3dna_profile_no - ), + "bp_step_{0!s}_{1:04d}.dat.gz".format(run, x3dna_profile_no), ) np.savetxt(frame_x3dna_txt, frame_x3dna_output) logger.debug( @@ -953,9 +939,7 @@ def collect(self, **kwargs): ) # if we get here then we haven't found anything interesting if len(self.profiles) == length: - logger.info( - "Collected X3DNA profiles for %d frames", len(self.profiles) - ) + logger.info("Collected X3DNA profiles for %d frames", len(self.profiles)) else: logger.warning( "Missing data: Found %d X3DNA profiles from %d frames.", @@ -1073,8 +1057,10 @@ def run(self, **kwargs): except OSError: pass if len(x3dna_profiles) != 1: - err_msg = "Got {0} profiles ({1}) --- should be 1 (time step {2})".format( - len(x3dna_profiles), x3dna_profiles.keys(), ts + err_msg = ( + "Got {0} profiles ({1}) --- should be 1 (time step {2})".format( + len(x3dna_profiles), x3dna_profiles.keys(), ts + ) ) logger.error(err_msg) warnings.warn(err_msg) diff --git a/package/MDAnalysis/analysis/lineardensity.py b/package/MDAnalysis/analysis/lineardensity.py index 369ade9b37..77ea48bf43 100644 --- a/package/MDAnalysis/analysis/lineardensity.py +++ b/package/MDAnalysis/analysis/lineardensity.py @@ -62,9 +62,7 @@ def _deprecation_warning(self, key): def __getitem__(self, key): if key in self._deprecation_dict.keys(): self._deprecation_warning(key) - return super(Results, self).__getitem__( - self._deprecation_dict[key] - ) + return super(Results, self).__getitem__(self._deprecation_dict[key]) return super(Results, self).__getitem__(key) def __getattr__(self, attr): @@ -214,9 +212,7 @@ def get_supported_backends(cls): ) def __init__(self, select, grouping="atoms", binsize=0.25, **kwargs): - super(LinearDensity, self).__init__( - select.universe.trajectory, **kwargs - ) + super(LinearDensity, self).__init__(select.universe.trajectory, **kwargs) # allows use of run(parallel=True) self._ags = [select] self._universe = select.universe @@ -267,23 +263,17 @@ def __init__(self, select, grouping="atoms", binsize=0.25, **kwargs): self.charges = self._ags[0].total_charge(compound=self.grouping) else: - raise AttributeError( - f"{self.grouping} is not a valid value for grouping." - ) + raise AttributeError(f"{self.grouping} is not a valid value for grouping.") @staticmethod def _custom_aggregator(results): # NB: the *stddev values here are not the standard deviation, # but the variance. The stddev is calculated in _conclude() - mass_density = np.sum( - [entry["mass_density"] for entry in results], axis=0 - ) + mass_density = np.sum([entry["mass_density"] for entry in results], axis=0) mass_density_stddev = np.sum( [entry["mass_density_stddev"] for entry in results], axis=0 ) - charge_density = np.sum( - [entry["charge_density"] for entry in results], axis=0 - ) + charge_density = np.sum([entry["charge_density"] for entry in results], axis=0) charge_density_stddev = np.sum( [entry["charge_density_stddev"] for entry in results], axis=0 ) @@ -316,9 +306,7 @@ def _single_frame(self): self.charges = self._ags[0].total_charge(compound=self.grouping) else: - raise AttributeError( - f"{self.grouping} is not a valid value for grouping." - ) + raise AttributeError(f"{self.grouping} is not a valid value for grouping.") self.group = getattr(self._ags[0], self.grouping) self._ags[0].wrap(compound=self.grouping) @@ -380,19 +368,17 @@ def _conclude(self): # radicand_mass and radicand_charge are therefore calculated first # and negative values set to 0 before the square root # is calculated. - radicand_mass = self.results[dim][ - "mass_density_stddev" - ] - np.square(self.results[dim]["mass_density"]) + radicand_mass = self.results[dim]["mass_density_stddev"] - np.square( + self.results[dim]["mass_density"] + ) radicand_mass[radicand_mass < 0] = 0 self.results[dim]["mass_density_stddev"] = np.sqrt(radicand_mass) - radicand_charge = self.results[dim][ - "charge_density_stddev" - ] - np.square(self.results[dim]["charge_density"]) - radicand_charge[radicand_charge < 0] = 0 - self.results[dim]["charge_density_stddev"] = np.sqrt( - radicand_charge + radicand_charge = self.results[dim]["charge_density_stddev"] - np.square( + self.results[dim]["charge_density"] ) + radicand_charge[radicand_charge < 0] = 0 + self.results[dim]["charge_density_stddev"] = np.sqrt(radicand_charge) for dim in ["x", "y", "z"]: # norming factor, units of mol^-1 cm^3 @@ -404,8 +390,7 @@ def _conclude(self): @deprecate( release="2.2.0", remove="3.0.0", - message="It will be replaced by a :meth:`_reduce` " - "method in the future", + message="It will be replaced by a :meth:`_reduce` " "method in the future", ) def _add_other_results(self, other): """For parallel analysis""" diff --git a/package/MDAnalysis/analysis/nucleicacids.py b/package/MDAnalysis/analysis/nucleicacids.py index bf68a954cb..9e84119ded 100644 --- a/package/MDAnalysis/analysis/nucleicacids.py +++ b/package/MDAnalysis/analysis/nucleicacids.py @@ -182,9 +182,7 @@ def __init__( selection2: List[mda.AtomGroup], **kwargs, ) -> None: - super(NucPairDist, self).__init__( - selection1[0].universe.trajectory, **kwargs - ) + super(NucPairDist, self).__init__(selection1[0].universe.trajectory, **kwargs) if len(selection1) != len(selection2): raise ValueError("Selections must be same length") @@ -268,9 +266,7 @@ def select_strand_atoms( elif pair[0].resname[0] in purines: a1, a2 = a1_name, a2_name else: - raise ValueError( - f"AtomGroup in {pair} is not a valid nucleic acid" - ) + raise ValueError(f"AtomGroup in {pair} is not a valid nucleic acid") ag1 = pair[0].atoms.select_atoms(f"name {a1}") ag2 = pair[1].atoms.select_atoms(f"name {a2}") @@ -293,9 +289,7 @@ def select_strand_atoms( return (sel1, sel2) def _prepare(self) -> None: - self.results.distances: np.ndarray = np.zeros( - [self.n_frames, self._n_sel] - ) + self.results.distances: np.ndarray = np.zeros([self.n_frames, self._n_sel]) def _single_frame(self) -> None: dist: np.ndarray = calc_bonds(self._s1.positions, self._s2.positions) @@ -581,9 +575,7 @@ def __init__( ) ) - super(MinorPairDist, self).__init__( - selections[0], selections[1], **kwargs - ) + super(MinorPairDist, self).__init__(selections[0], selections[1], **kwargs) class MajorPairDist(NucPairDist): @@ -679,6 +671,4 @@ def __init__( ) ) - super(MajorPairDist, self).__init__( - selections[0], selections[1], **kwargs - ) + super(MajorPairDist, self).__init__(selections[0], selections[1], **kwargs) diff --git a/package/MDAnalysis/analysis/pca.py b/package/MDAnalysis/analysis/pca.py index fddbf7d009..d36ffea00b 100644 --- a/package/MDAnalysis/analysis/pca.py +++ b/package/MDAnalysis/analysis/pca.py @@ -614,12 +614,8 @@ def project_single_frame(self, components=None, group=None, anchor=None): non_pca_atoms = np.array([], dtype=int) for res in group.residues: # n_common is the number of pca atoms in a residue - n_common = pca_res_counts[ - np.where(pca_res_indices == res.resindex) - ][0] - non_pca_atoms = np.append( - non_pca_atoms, res.atoms.n_atoms - n_common - ) + n_common = pca_res_counts[np.where(pca_res_indices == res.resindex)][0] + non_pca_atoms = np.append(non_pca_atoms, res.atoms.n_atoms - n_common) # index_extrapolate records the anchor number for each non-PCA atom index_extrapolate = np.repeat( np.arange(anchors.atoms.n_atoms), non_pca_atoms @@ -724,9 +720,7 @@ def rmsip(self, other, n_components=None): b = other.results.p_components except AttributeError: if isinstance(other, type(self)): - raise ValueError( - "Call run() on the other PCA before using rmsip" - ) + raise ValueError("Call run() on the other PCA before using rmsip") else: raise ValueError("other must be another PCA class") @@ -773,9 +767,7 @@ def cumulative_overlap(self, other, i=0, n_components=None): try: a = self.results.p_components except AttributeError: - raise ValueError( - "Call run() on the PCA before using cumulative_overlap" - ) + raise ValueError("Call run() on the PCA before using cumulative_overlap") try: b = other.results.p_components diff --git a/package/MDAnalysis/analysis/polymer.py b/package/MDAnalysis/analysis/polymer.py index 3b78b0b0eb..68a2679811 100644 --- a/package/MDAnalysis/analysis/polymer.py +++ b/package/MDAnalysis/analysis/polymer.py @@ -83,14 +83,11 @@ def sort_backbone(backbone): "".format(",".join(str(a) for a in branches)) ) - caps = [ - atom for atom in backbone if len(atom.bonded_atoms & backbone) == 1 - ] + caps = [atom for atom in backbone if len(atom.bonded_atoms & backbone) == 1] if not caps: # cyclical structure raise ValueError( - "Could not find starting point of backbone, " - "is the backbone cyclical?" + "Could not find starting point of backbone, " "is the backbone cyclical?" ) # arbitrarily choose one of the capping atoms to be the startpoint diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index c3459ac65f..5063d522de 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -264,8 +264,7 @@ def __init__( if self.norm not in ["rdf", "density", "none"]: raise ValueError( - f"'{self.norm}' is an invalid norm. " - "Use 'rdf', 'density' or 'none'." + f"'{self.norm}' is an invalid norm. " "Use 'rdf', 'density' or 'none'." ) self.backend = backend @@ -589,9 +588,7 @@ def __init__( backend="serial", **kwargs, ): - super(InterRDF_s, self).__init__( - ags[0][0].universe.trajectory, **kwargs - ) + super(InterRDF_s, self).__init__(ags[0][0].universe.trajectory, **kwargs) warnings.warn( "The `u` attribute is superflous and will be removed " @@ -605,8 +602,7 @@ def __init__( if self.norm not in ["rdf", "density", "none"]: raise ValueError( - f"'{self.norm}' is an invalid norm. " - "Use 'rdf', 'density' or 'none'." + f"'{self.norm}' is an invalid norm. " "Use 'rdf', 'density' or 'none'." ) if density: diff --git a/package/MDAnalysis/analysis/results.py b/package/MDAnalysis/analysis/results.py index 7708f3dd88..37db403d9a 100644 --- a/package/MDAnalysis/analysis/results.py +++ b/package/MDAnalysis/analysis/results.py @@ -101,9 +101,7 @@ class in `scikit-learn`_. def _validate_key(self, key): if key in dir(self): - raise AttributeError( - f"'{key}' is a protected dictionary attribute" - ) + raise AttributeError(f"'{key}' is a protected dictionary attribute") elif isinstance(key, str) and not key.isidentifier(): raise ValueError(f"'{key}' is not a valid attribute") @@ -128,17 +126,13 @@ def __getattr__(self, attr): try: return self[attr] except KeyError as err: - raise AttributeError( - f"'Results' object has no attribute '{attr}'" - ) from err + raise AttributeError(f"'Results' object has no attribute '{attr}'") from err def __delattr__(self, attr): try: del self[attr] except KeyError as err: - raise AttributeError( - f"'Results' object has no attribute '{attr}'" - ) from err + raise AttributeError(f"'Results' object has no attribute '{attr}'") from err def __getstate__(self): return self.data diff --git a/package/MDAnalysis/analysis/rms.py b/package/MDAnalysis/analysis/rms.py index 55a1322a75..d4576ed781 100644 --- a/package/MDAnalysis/analysis/rms.py +++ b/package/MDAnalysis/analysis/rms.py @@ -312,8 +312,7 @@ def process_selection(select): select = {"mobile": select[0], "reference": select[1]} except IndexError: raise IndexError( - "select must contain two selection strings " - "(reference, mobile)" + "select must contain two selection strings " "(reference, mobile)" ) from None elif type(select) is dict: # compatability hack to use new nomenclature @@ -552,9 +551,7 @@ def __init__( ) logger.exception(err) raise SelectionError(err) - logger.info( - "RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms)) - ) + logger.info("RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms))) mass_mismatches = ( np.absolute((self.ref_atoms.masses - self.mobile_atoms.masses)) > self.tol_mass @@ -596,9 +593,7 @@ def __init__( # *groupselections* groups each a dict with reference/mobile self._groupselections_atoms = [ { - "reference": self.reference.universe.select_atoms( - *s["reference"] - ), + "reference": self.reference.universe.select_atoms(*s["reference"]), "mobile": self.atomgroup.universe.select_atoms(*s["mobile"]), } for s in self.groupselections @@ -661,23 +656,18 @@ def __init__( get_weights(atoms["mobile"], weights) except Exception as e: raise type(e)( - str(e) - + " happens in selection %s" % selection["mobile"] + str(e) + " happens in selection %s" % selection["mobile"] ) def _prepare(self): self._n_atoms = self.mobile_atoms.n_atoms if not self.weights_groupselections: - if not iterable( - self.weights - ): # apply 'mass' or 'None' to groupselections + if not iterable(self.weights): # apply 'mass' or 'None' to groupselections self.weights_groupselections = [self.weights] * len( self.groupselections ) else: - self.weights_groupselections = [None] * len( - self.groupselections - ) + self.weights_groupselections = [None] * len(self.groupselections) for igroup, (weights, atoms) in enumerate( zip(self.weights_groupselections, self._groupselections_atoms) @@ -695,9 +685,9 @@ def _prepare(self): self.weights_select = np.asarray( self.weights_select, dtype=np.float64 ) / np.mean(self.weights_select) - self.weights_ref = np.asarray( - self.weights_ref, dtype=np.float64 - ) / np.mean(self.weights_ref) + self.weights_ref = np.asarray(self.weights_ref, dtype=np.float64) / np.mean( + self.weights_ref + ) current_frame = self.reference.universe.trajectory.ts.frame @@ -712,9 +702,9 @@ def _prepare(self): if self._groupselections_atoms: self._groupselections_ref_coords64 = [ ( - self.reference.select_atoms( - *s["reference"] - ).positions.astype(np.float64) + self.reference.select_atoms(*s["reference"]).positions.astype( + np.float64 + ) ) for s in self.groupselections ] @@ -747,9 +737,7 @@ def _get_aggregator(self): return ResultsGroup(lookup={"rmsd": ResultsGroup.ndarray_vstack}) def _single_frame(self): - mobile_com = self.mobile_atoms.center(self.weights_select).astype( - np.float64 - ) + mobile_com = self.mobile_atoms.center(self.weights_select).astype(np.float64) self._mobile_coordinates64[:] = self.mobile_atoms.positions self._mobile_coordinates64 -= mobile_com @@ -765,14 +753,12 @@ def _single_frame(self): # left** so that we can easily use broadcasting and save one # expensive numpy transposition. - self.results.rmsd[self._frame_index, 2] = ( - qcp.CalcRMSDRotationalMatrix( - self._ref_coordinates64, - self._mobile_coordinates64, - self._n_atoms, - self._rot, - self.weights_select, - ) + self.results.rmsd[self._frame_index, 2] = qcp.CalcRMSDRotationalMatrix( + self._ref_coordinates64, + self._mobile_coordinates64, + self._n_atoms, + self._rot, + self.weights_select, ) self._R[:, :] = self._rot.reshape(3, 3) @@ -804,14 +790,12 @@ def _single_frame(self): else: # only calculate RMSD by setting the Rmatrix to None (no need # to carry out the rotation as we already get the optimum RMSD) - self.results.rmsd[self._frame_index, 2] = ( - qcp.CalcRMSDRotationalMatrix( - self._ref_coordinates64, - self._mobile_coordinates64, - self._n_atoms, - None, - self.weights_select, - ) + self.results.rmsd[self._frame_index, 2] = qcp.CalcRMSDRotationalMatrix( + self._ref_coordinates64, + self._mobile_coordinates64, + self._n_atoms, + None, + self.weights_select, ) @property @@ -975,9 +959,7 @@ def _prepare(self): def _single_frame(self): k = self._frame_index - self.sumsquares += (k / (k + 1.0)) * ( - self.atomgroup.positions - self.mean - ) ** 2 + self.sumsquares += (k / (k + 1.0)) * (self.atomgroup.positions - self.mean) ** 2 self.mean = (k * self.mean + self.atomgroup.positions) / (k + 1) def _conclude(self): @@ -986,8 +968,7 @@ def _conclude(self): if not (self.results.rmsf >= 0).all(): raise ValueError( - "Some RMSF values negative; overflow " - + "or underflow occurred" + "Some RMSF values negative; overflow " + "or underflow occurred" ) @property diff --git a/package/MDAnalysis/auxiliary/EDR.py b/package/MDAnalysis/auxiliary/EDR.py index 8b9149690e..74d1579d16 100644 --- a/package/MDAnalysis/auxiliary/EDR.py +++ b/package/MDAnalysis/auxiliary/EDR.py @@ -316,9 +316,7 @@ class EDRReader(base.AuxReader): def __init__(self, filename: str, convert_units: bool = True, **kwargs): if not HAS_PYEDR: - raise ImportError( - "EDRReader: To read EDR files please install " "pyedr." - ) + raise ImportError("EDRReader: To read EDR files please install " "pyedr.") self._auxdata = Path(filename).resolve() self.data_dict = pyedr.edr_to_dict(filename) self.unit_dict = pyedr.get_unit_dictionary(filename) @@ -348,8 +346,7 @@ def _convert_units(self): self.unit_dict[term] = units.MDANALYSIS_BASE_UNITS[unit_type] if unknown_units: warnings.warn( - "Could not find unit type for the following " - f"units: {unknown_units}" + "Could not find unit type for the following " f"units: {unknown_units}" ) def _memory_usage(self): @@ -375,8 +372,7 @@ def _read_next_step(self) -> EDRStep: new_step = self.step + 1 if new_step < self.n_steps: auxstep._data = { - term: self.data_dict[term][self.step + 1] - for term in self.terms + term: self.data_dict[term][self.step + 1] for term in self.terms } auxstep.step = new_step return auxstep diff --git a/package/MDAnalysis/auxiliary/base.py b/package/MDAnalysis/auxiliary/base.py index 29fbaf999a..12ae24cf61 100644 --- a/package/MDAnalysis/auxiliary/base.py +++ b/package/MDAnalysis/auxiliary/base.py @@ -193,9 +193,7 @@ def _time_selector(self, new): select = self._select_time except AttributeError: warnings.warn( - "{} does not support time selection".format( - self.__class__.__name__ - ) + "{} does not support time selection".format(self.__class__.__name__) ) else: # check *new* is valid before setting; _select_time should raise @@ -234,9 +232,7 @@ def _data_selector(self, new): select = self._select_data except AttributeError: warnings.warn( - "{} does not support data selection".format( - self.__class__.__name__ - ) + "{} does not support data selection".format(self.__class__.__name__) ) else: # check *new* is valid before setting; _select_data should raise an @@ -329,9 +325,7 @@ class AuxReader(metaclass=_AuxReaderMeta): "_auxdata", ] - def __init__( - self, represent_ts_as="closest", auxname=None, cutoff=None, **kwargs - ): + def __init__(self, represent_ts_as="closest", auxname=None, cutoff=None, **kwargs): # allow auxname to be optional for when using reader separate from # trajectory. self.auxname = auxname @@ -631,9 +625,7 @@ def step_to_frame(self, step, ts, return_time_diff=False): return None time_frame_0 = ts.time - ts.frame * ts.dt # assumes ts.dt is constant time_step = self.step_to_time(step) - frame_index = int( - math.floor((time_step - time_frame_0 + ts.dt / 2.0) / ts.dt) - ) + frame_index = int(math.floor((time_step - time_frame_0 + ts.dt / 2.0) / ts.dt)) if not return_time_diff: return frame_index else: @@ -658,9 +650,7 @@ def move_to_ts(self, ts): # figure out what step we want to end up at if self.constant_dt: # if dt constant, calculate from dt/offset/etc - step = int( - math.floor((ts.time - ts.dt / 2 - self.initial_time) / self.dt) - ) + step = int(math.floor((ts.time - ts.dt / 2 - self.initial_time) / self.dt)) # if we're out of range of the number of steps, reset back step = max(min(step, self.n_steps - 1), -1) else: @@ -749,11 +739,7 @@ def __getitem__(self, i): stop = ( i.stop if i.stop == self.n_steps - else ( - self._check_index(i.stop) - if i.stop is not None - else self.n_steps - ) + else (self._check_index(i.stop) if i.stop is not None else self.n_steps) ) step = i.step or 1 if not isinstance(step, numbers.Integral) or step < 1: @@ -787,9 +773,7 @@ def _slice_iter(self, i): def _go_to_step(self, i): """Move to and read i-th auxiliary step.""" # Need to define in each auxiliary reader - raise NotImplementedError( - "BUG: Override _go_to_step() in auxiliary reader!" - ) + raise NotImplementedError("BUG: Override _go_to_step() in auxiliary reader!") def _reset_frame_data(self): self.frame_data = {} @@ -853,9 +837,7 @@ def calc_representative(self): value = cutoff_data[min_diff] elif self.represent_ts_as == "average": try: - value = np.mean( - np.array([val for val in cutoff_data.values()]), axis=0 - ) + value = np.mean(np.array([val for val in cutoff_data.values()]), axis=0) except TypeError: # for readers like EDRReader, the above does not work # because each step contains a dictionary of numpy arrays @@ -967,8 +949,7 @@ def get_description(self): AuxReader. """ description = { - attr.strip("_"): getattr(self, attr) - for attr in self.required_attrs + attr.strip("_"): getattr(self, attr) for attr in self.required_attrs } return description diff --git a/package/MDAnalysis/converters/OpenMM.py b/package/MDAnalysis/converters/OpenMM.py index 76a743b773..9d0c6a6531 100644 --- a/package/MDAnalysis/converters/OpenMM.py +++ b/package/MDAnalysis/converters/OpenMM.py @@ -108,9 +108,7 @@ def _read_first_frame(self): self.ts.triclinic_dimensions = self.convert_pos_from_native( self.ts.triclinic_dimensions, inplace=False ) - self.ts.dimensions[3:] = _sanitize_box_angles( - self.ts.dimensions[3:] - ) + self.ts.dimensions[3:] = _sanitize_box_angles(self.ts.dimensions[3:]) self.convert_velocities_from_native(self.ts._velocities) self.convert_forces_from_native(self.ts._forces) self.convert_time_from_native(self.ts.dt) @@ -137,9 +135,7 @@ def _mda_timestep_from_omm_context(self): ts.data["kinetic_energy"] = ( state.getKineticEnergy().in_units_of(u.kilojoule / u.mole)._value ) - ts.triclinic_dimensions = state.getPeriodicBoxVectors( - asNumpy=True - )._value + ts.triclinic_dimensions = state.getPeriodicBoxVectors(asNumpy=True)._value ts.dimensions[3:] = _sanitize_box_angles(ts.dimensions[3:]) ts.positions = state.getPositions(asNumpy=True)._value ts.velocities = state.getVelocities(asNumpy=True)._value @@ -183,9 +179,7 @@ def _read_first_frame(self): self.ts.triclinic_dimensions = self.convert_pos_from_native( self.ts.triclinic_dimensions, inplace=False ) - self.ts.dimensions[3:] = _sanitize_box_angles( - self.ts.dimensions[3:] - ) + self.ts.dimensions[3:] = _sanitize_box_angles(self.ts.dimensions[3:]) def _mda_timestep_from_omm_app(self): """Construct Timestep object from OpenMM Application object""" diff --git a/package/MDAnalysis/converters/OpenMMParser.py b/package/MDAnalysis/converters/OpenMMParser.py index 03fa06a60b..4851f7bac9 100644 --- a/package/MDAnalysis/converters/OpenMMParser.py +++ b/package/MDAnalysis/converters/OpenMMParser.py @@ -194,9 +194,7 @@ def _mda_topology_from_omm_topology(self, omm_topology): " but it will be removed in 3.0)." ) - attrs.append( - Elements(np.array(validated_elements, dtype=object)) - ) + attrs.append(Elements(np.array(validated_elements, dtype=object))) else: wmsg = ( diff --git a/package/MDAnalysis/converters/ParmEd.py b/package/MDAnalysis/converters/ParmEd.py index e26f880c9f..57f6042ffb 100644 --- a/package/MDAnalysis/converters/ParmEd.py +++ b/package/MDAnalysis/converters/ParmEd.py @@ -238,9 +238,7 @@ def convert(self, obj): "id", ): try: - akwargs[MDA2PMD.get(attrname, attrname)] = getattr( - atom, attrname - ) + akwargs[MDA2PMD.get(attrname, attrname)] = getattr(atom, attrname) except AttributeError: pass try: @@ -260,9 +258,7 @@ def convert(self, obj): chain_seg["inscode"] = atom.icode except AttributeError: pass - atom_kwargs.append( - (akwargs, resname, atom.resid, chain_seg, xyz, vel) - ) + atom_kwargs.append((akwargs, resname, atom.resid, chain_seg, xyz, vel)) struct = pmd.Structure() @@ -288,9 +284,7 @@ def convert(self, obj): struct.box = None if hasattr(ag_or_ts, "universe"): - atomgroup = { - atom: index for index, atom in enumerate(list(ag_or_ts)) - } + atomgroup = {atom: index for index, atom in enumerate(list(ag_or_ts))} get_atom_indices = functools.partial( get_indices_from_subset, atomgroup=atomgroup, @@ -306,9 +300,7 @@ def convert(self, obj): pass else: for p in params: - atoms = [ - struct.atoms[i] for i in map(get_atom_indices, p.indices) - ] + atoms = [struct.atoms[i] for i in map(get_atom_indices, p.indices)] try: for obj in p.type: bond = pmd.Bond(*atoms, type=obj.type, order=obj.order) @@ -328,16 +320,12 @@ def convert(self, obj): # dihedrals try: - params = ag_or_ts.dihedrals.atomgroup_intersection( - ag_or_ts, strict=True - ) + params = ag_or_ts.dihedrals.atomgroup_intersection(ag_or_ts, strict=True) except AttributeError: pass else: for p in params: - atoms = [ - struct.atoms[i] for i in map(get_atom_indices, p.indices) - ] + atoms = [struct.atoms[i] for i in map(get_atom_indices, p.indices)] try: for obj in p.type: imp = getattr(obj, "improper", False) @@ -353,9 +341,7 @@ def convert(self, obj): btype = getattr(p.type, "type", None) imp = getattr(p.type, "improper", False) ign = getattr(p.type, "ignore_end", False) - dih = pmd.Dihedral( - *atoms, type=btype, improper=imp, ignore_end=ign - ) + dih = pmd.Dihedral(*atoms, type=btype, improper=imp, ignore_end=ign) struct.dihedrals.append(dih) if isinstance(dih.type, pmd.DihedralType): struct.dihedral_types.append(dih.type) @@ -392,10 +378,7 @@ def convert(self, obj): pass else: for v in values: - atoms = [ - struct.atoms[i] - for i in map(get_atom_indices, v.indices) - ] + atoms = [struct.atoms[i] for i in map(get_atom_indices, v.indices)] try: for parmed_obj in v.type: diff --git a/package/MDAnalysis/converters/ParmEdParser.py b/package/MDAnalysis/converters/ParmEdParser.py index 331f14e279..0fdbae4c74 100644 --- a/package/MDAnalysis/converters/ParmEdParser.py +++ b/package/MDAnalysis/converters/ParmEdParser.py @@ -311,9 +311,7 @@ def parse(self, **kwargs): bond_orders = list(map(squash_identical, bond_orders)) attrs.append( - Bonds( - bond_values, types=bond_types, guessed=False, order=bond_orders - ) + Bonds(bond_values, types=bond_types, guessed=False, order=bond_orders) ) for pmdlist, na, values, types in ( diff --git a/package/MDAnalysis/converters/RDKitInferring.py b/package/MDAnalysis/converters/RDKitInferring.py index 843986371a..6c42464b56 100644 --- a/package/MDAnalysis/converters/RDKitInferring.py +++ b/package/MDAnalysis/converters/RDKitInferring.py @@ -92,9 +92,7 @@ ) # available since 2022.09.1 -def reorder_atoms( - mol: "Chem.Mol", field: str = "_MDAnalysis_index" -) -> "Chem.Mol": +def reorder_atoms(mol: "Chem.Mol", field: str = "_MDAnalysis_index") -> "Chem.Mol": """Reorder atoms based on the given field. Defaults to sorting in the same order as the input AtomGroup. @@ -394,9 +392,7 @@ def _standardize_patterns( self._rebuild_conjugated_bonds(mol, max_iter) # list of sanitized reactions - reactions = [ - ReactionFromSmarts(rxn) for rxn in self.STANDARDIZATION_REACTIONS - ] + reactions = [ReactionFromSmarts(rxn) for rxn in self.STANDARDIZATION_REACTIONS] # fragment mol (reactions must have single reactant and product) fragments = list( @@ -485,17 +481,13 @@ def _rebuild_conjugated_bonds( # there's usually an even number of matches for this pattern = Chem.MolFromSmarts("[*-{1-2}]-,=[*+0]=,#[*+0]") # pattern used to finish fixing a series of conjugated bonds - base_end_pattern = Chem.MolFromSmarts( - "[*-{1-2}]-,=[*+0]=,#[*+0]-,=[*-{1-2}]" - ) + base_end_pattern = Chem.MolFromSmarts("[*-{1-2}]-,=[*+0]=,#[*+0]-,=[*-{1-2}]") # used when there's an odd number of matches for `pattern` odd_end_pattern = Chem.MolFromSmarts( "[*-]-[*+0]=[*+0]-[*-,$([#7;X3;v3]),$([#6+0,#7+1]=O),$([S;D4;v4]-[O-])]" ) # number of unique matches with the pattern - n_matches = len( - {match[0] for match in mol.GetSubstructMatches(pattern)} - ) + n_matches = len({match[0] for match in mol.GetSubstructMatches(pattern)}) # nothing to standardize if n_matches == 0: return @@ -523,16 +515,12 @@ def _rebuild_conjugated_bonds( # [*-]-*=*-[C,N+]=O --> *=*-*=[C,N+]-[O-] # transform the =O to -[O-] if ( - term_atom.GetAtomicNum() == 6 - and term_atom.GetFormalCharge() == 0 + term_atom.GetAtomicNum() == 6 and term_atom.GetFormalCharge() == 0 ) or ( - term_atom.GetAtomicNum() == 7 - and term_atom.GetFormalCharge() == 1 + term_atom.GetAtomicNum() == 7 and term_atom.GetFormalCharge() == 1 ): for neighbor in term_atom.GetNeighbors(): - bond = mol.GetBondBetweenAtoms( - anion2, neighbor.GetIdx() - ) + bond = mol.GetBondBetweenAtoms(anion2, neighbor.GetIdx()) if ( neighbor.GetAtomicNum() == 8 and bond.GetBondTypeAsDouble() == 2 @@ -544,13 +532,10 @@ def _rebuild_conjugated_bonds( # [*-]-*=*-[Sv4]-[O-] --> *=*-*=[Sv6]=O # transform -[O-] to =O elif ( - term_atom.GetAtomicNum() == 16 - and term_atom.GetFormalCharge() == 0 + term_atom.GetAtomicNum() == 16 and term_atom.GetFormalCharge() == 0 ): for neighbor in term_atom.GetNeighbors(): - bond = mol.GetBondBetweenAtoms( - anion2, neighbor.GetIdx() - ) + bond = mol.GetBondBetweenAtoms(anion2, neighbor.GetIdx()) if ( neighbor.GetAtomicNum() == 8 and neighbor.GetFormalCharge() == -1 diff --git a/package/MDAnalysis/converters/RDKitParser.py b/package/MDAnalysis/converters/RDKitParser.py index 90069ebfb1..22e0851b22 100644 --- a/package/MDAnalysis/converters/RDKitParser.py +++ b/package/MDAnalysis/converters/RDKitParser.py @@ -215,9 +215,7 @@ def parse(self, **kwargs): return top # check if multiple charges present - if atom.HasProp("_GasteigerCharge") and ( - atom.HasProp("_TriposPartialCharge") - ): + if atom.HasProp("_GasteigerCharge") and (atom.HasProp("_TriposPartialCharge")): warnings.warn( "Both _GasteigerCharge and _TriposPartialCharge properties " "are present. Using Gasteiger charges by default." @@ -259,9 +257,7 @@ def parse(self, **kwargs): except KeyError: # partial charge (MOL2 only) try: - charges.append( - atom.GetDoubleProp("_TriposPartialCharge") - ) + charges.append(atom.GetDoubleProp("_TriposPartialCharge")) except KeyError: pass diff --git a/package/MDAnalysis/coordinates/CRD.py b/package/MDAnalysis/coordinates/CRD.py index e762c83767..16a0c07ee2 100644 --- a/package/MDAnalysis/coordinates/CRD.py +++ b/package/MDAnalysis/coordinates/CRD.py @@ -82,10 +82,7 @@ def _read_first_frame(self): np.array(line[20:50].split()[0:3], dtype=float) ) except Exception: - errmsg = ( - f"Check CRD format at line {linenum}: " - f"{line.rstrip()}" - ) + errmsg = f"Check CRD format at line {linenum}: " f"{line.rstrip()}" raise ValueError(errmsg) from None self.n_atoms = len(coords_list) @@ -101,8 +98,7 @@ def _read_first_frame(self): if self.n_atoms != natoms: raise ValueError( "Found %d coordinates in %r but the header claims that there " - "should be %d coordinates." - % (self.n_atoms, self.filename, natoms) + "should be %d coordinates." % (self.n_atoms, self.filename, natoms) ) def Writer(self, filename, **kwargs): @@ -217,9 +213,7 @@ def write(self, selection, frame=None): frame = 0 # should catch cases when we are analyzing a single PDB (?) atoms = selection.atoms # make sure to use atoms (Issue 46) - coor = ( - atoms.positions - ) # can write from selection == Universe (Issue 49) + coor = atoms.positions # can write from selection == Universe (Issue 49) n_atoms = len(atoms) # Detect which format string we're using to output (EXT or not) @@ -271,9 +265,7 @@ def write(self, selection, frame=None): with util.openany(self.filename, "wt") as crd: # Write Title crd.write( - self.fmt["TITLE"].format( - frame=frame, where=u.trajectory.filename - ) + self.fmt["TITLE"].format(frame=frame, where=u.trajectory.filename) ) crd.write("*\n") diff --git a/package/MDAnalysis/coordinates/DCD.py b/package/MDAnalysis/coordinates/DCD.py index 88c8d76b3e..6c43a475bf 100644 --- a/package/MDAnalysis/coordinates/DCD.py +++ b/package/MDAnalysis/coordinates/DCD.py @@ -117,9 +117,10 @@ class DCDReader(base.ReaderBase): .. _DCDplugin: http://www.ks.uiuc.edu/Research/vmd/plugins/doxygen/dcdplugin_8c-source.html#l00947 .. _wiki: https://github.com/MDAnalysis/mdanalysis/wiki/FileFormats#dcd """ - format = 'DCD' - flavor = 'CHARMM' - units = {'time': 'AKMA', 'length': 'Angstrom'} + + format = "DCD" + flavor = "CHARMM" + units = {"time": "AKMA", "length": "Angstrom"} @store_init_arguments def __init__(self, filename, convert_units=True, dt=None, **kwargs): @@ -139,18 +140,16 @@ def __init__(self, filename, convert_units=True, dt=None, **kwargs): .. versionchanged:: 0.17.0 Changed to use libdcd.pyx library and removed the correl function """ - super(DCDReader, self).__init__( - filename, convert_units=convert_units, **kwargs) + super(DCDReader, self).__init__(filename, convert_units=convert_units, **kwargs) self._file = DCDFile(self.filename) - self.n_atoms = self._file.header['natoms'] + self.n_atoms = self._file.header["natoms"] - delta = mdaunits.convert(self._file.header['delta'], - self.units['time'], 'ps') + delta = mdaunits.convert(self._file.header["delta"], self.units["time"], "ps") if dt is None: - dt = delta * self._file.header['nsavc'] - self.skip_timestep = self._file.header['nsavc'] + dt = delta * self._file.header["nsavc"] + self.skip_timestep = self._file.header["nsavc"] - self._ts_kwargs['dt'] = dt + self._ts_kwargs["dt"] = dt self.ts = self._Timestep(self.n_atoms, **self._ts_kwargs) frame = self._file.read() # reset trajectory @@ -162,18 +161,20 @@ def __init__(self, filename, convert_units=True, dt=None, **kwargs): self.ts = self._frame_to_ts(frame, self.ts) # these should only be initialized once self.ts.dt = dt - warnings.warn("DCDReader currently makes independent timesteps" - " by copying self.ts while other readers update" - " self.ts inplace. This behavior will be changed in" - " 3.0 to be the same as other readers. Read more at" - " https://github.com/MDAnalysis/mdanalysis/issues/3889" - " to learn if this change in behavior might affect you.", - category=DeprecationWarning) + warnings.warn( + "DCDReader currently makes independent timesteps" + " by copying self.ts while other readers update" + " self.ts inplace. This behavior will be changed in" + " 3.0 to be the same as other readers. Read more at" + " https://github.com/MDAnalysis/mdanalysis/issues/3889" + " to learn if this change in behavior might affect you.", + category=DeprecationWarning, + ) @staticmethod def parse_n_atoms(filename, **kwargs): with DCDFile(filename) as f: - n_atoms = f.header['natoms'] + n_atoms = f.header["natoms"] return n_atoms def close(self): @@ -190,7 +191,7 @@ def _reopen(self): self.ts.frame = 0 self._frame = -1 self._file.close() - self._file.open('r') + self._file.open("r") def _read_frame(self, i): """read frame i""" @@ -201,9 +202,9 @@ def _read_frame(self, i): def _read_next_timestep(self, ts=None): """copy next frame into timestep""" if self._frame == self.n_frames - 1: - raise IOError('trying to go over trajectory limit') + raise IOError("trying to go over trajectory limit") if ts is None: - #TODO remove copying the ts in 3.0 + # TODO remove copying the ts in 3.0 ts = self.ts.copy() frame = self._file.read() self._frame += 1 @@ -220,21 +221,23 @@ def Writer(self, filename, n_atoms=None, **kwargs): n_atoms=n_atoms, dt=self.ts.dt, convert_units=self.convert_units, - **kwargs) + **kwargs + ) def _frame_to_ts(self, frame, ts): """convert a dcd-frame to a :class:`TimeStep`""" ts.frame = self._frame - ts.time = (ts.frame + self._file.header['istart']/self._file.header['nsavc']) * self.ts.dt - ts.data['step'] = self._file.tell() + ts.time = ( + ts.frame + self._file.header["istart"] / self._file.header["nsavc"] + ) * self.ts.dt + ts.data["step"] = self._file.tell() # The original unitcell is read as ``[A, gamma, B, beta, alpha, C]`` _ts_order = [0, 2, 5, 4, 3, 1] uc = np.take(frame.unitcell, _ts_order) pi_2 = np.pi / 2 - if (-1.0 <= uc[3] <= 1.0) and (-1.0 <= uc[4] <= 1.0) and ( - -1.0 <= uc[5] <= 1.0): + if (-1.0 <= uc[3] <= 1.0) and (-1.0 <= uc[4] <= 1.0) and (-1.0 <= uc[5] <= 1.0): # This file was generated by Charmm, or by NAMD > 2.5, with the # angle cosines of the periodic cell angles written to the DCD # file. This formulation improves rounding behavior for orthogonal @@ -245,7 +248,7 @@ def _frame_to_ts(self, frame, ts): uc[4] = 90.0 - np.arcsin(uc[4]) * 90.0 / pi_2 uc[5] = 90.0 - np.arcsin(uc[5]) * 90.0 / pi_2 # heuristic sanity check: uc = A,B,C,alpha,beta,gamma - elif np.any(uc < 0.) or np.any(uc[3:] > 180.): + elif np.any(uc < 0.0) or np.any(uc[3:] > 180.0): # might be new CHARMM: box matrix vectors H = frame.unitcell.copy() e1, e2, e3 = H[[0, 1, 3]], H[[1, 2, 4]], H[[3, 4, 5]] @@ -267,8 +270,7 @@ def _frame_to_ts(self, frame, ts): @property def dimensions(self): - """unitcell dimensions (*A*, *B*, *C*, *alpha*, *beta*, *gamma*) - """ + """unitcell dimensions (*A*, *B*, *C*, *alpha*, *beta*, *gamma*)""" return self.ts.dimensions @property @@ -276,13 +278,9 @@ def dt(self): """timestep between frames""" return self.ts.dt - def timeseries(self, - asel=None, - atomgroup=None, - start=None, - stop=None, - step=None, - order='afc'): + def timeseries( + self, asel=None, atomgroup=None, start=None, stop=None, step=None, order="afc" + ): """Return a subset of coordinate data for an AtomGroup Parameters @@ -291,7 +289,7 @@ def timeseries(self, The :class:`~MDAnalysis.core.groups.AtomGroup` to read the coordinates from. Defaults to None, in which case the full set of coordinate data is returned. - + .. deprecated:: 2.7.0 asel argument will be renamed to atomgroup in 3.0.0 @@ -326,7 +324,8 @@ def timeseries(self, warnings.warn( "asel argument to timeseries will be renamed to" "'atomgroup' in 3.0, see #3911", - category=DeprecationWarning) + category=DeprecationWarning, + ) if atomgroup: raise ValueError("Cannot provide both asel and atomgroup kwargs") atomgroup = asel @@ -335,14 +334,14 @@ def timeseries(self, if atomgroup is not None: if len(atomgroup) == 0: - raise ValueError( - "Timeseries requires at least one atom to analyze") + raise ValueError("Timeseries requires at least one atom to analyze") atom_numbers = list(atomgroup.indices) else: atom_numbers = list(range(self.n_atoms)) frames = self._file.readframes( - start, stop, step, order=order, indices=atom_numbers) + start, stop, step, order=order, indices=atom_numbers + ) return frames.xyz @@ -361,21 +360,24 @@ class DCDWriter(base.WriterBase): not match the expectations of other software. """ - format = 'DCD' + + format = "DCD" multiframe = True - flavor = 'NAMD' - units = {'time': 'AKMA', 'length': 'Angstrom'} - - def __init__(self, - filename, - n_atoms, - convert_units=True, - step=1, - dt=1, - remarks='', - nsavc=1, - istart=0, - **kwargs): + flavor = "NAMD" + units = {"time": "AKMA", "length": "Angstrom"} + + def __init__( + self, + filename, + n_atoms, + convert_units=True, + step=1, + dt=1, + remarks="", + nsavc=1, + istart=0, + **kwargs + ): """Parameters ---------- filename : str @@ -412,10 +414,10 @@ def __init__(self, if n_atoms is None: raise ValueError("n_atoms argument is required") self.n_atoms = n_atoms - self._file = DCDFile(self.filename, 'w') + self._file = DCDFile(self.filename, "w") self.step = step self.dt = dt - dt = mdaunits.convert(dt, 'ps', self.units['time']) + dt = mdaunits.convert(dt, "ps", self.units["time"]) delta = float(dt) / nsavc istart = istart if istart is not None else nsavc self._file.write_header( @@ -424,7 +426,8 @@ def __init__(self, nsavc=nsavc, delta=delta, is_periodic=1, - istart=istart) + istart=istart, + ) def _write_next_frame(self, ag): """Write information associated with ``obj`` at current frame into trajectory @@ -458,8 +461,10 @@ def _write_next_frame(self, ag): try: dimensions = ts.dimensions.copy() except AttributeError: - wmsg = ('No dimensions set for current frame, zeroed unitcell ' - 'will be written') + wmsg = ( + "No dimensions set for current frame, zeroed unitcell " + "will be written" + ) warnings.warn(wmsg) dimensions = np.zeros(6) diff --git a/package/MDAnalysis/coordinates/DLPoly.py b/package/MDAnalysis/coordinates/DLPoly.py index 71297f978f..622668564a 100644 --- a/package/MDAnalysis/coordinates/DLPoly.py +++ b/package/MDAnalysis/coordinates/DLPoly.py @@ -35,7 +35,7 @@ from ..lib import util from ..lib.util import cached, store_init_arguments -_DLPOLY_UNITS = {'length': 'Angstrom', 'velocity': 'Angstrom/ps', 'time': 'ps'} +_DLPOLY_UNITS = {"length": "Angstrom", "velocity": "Angstrom/ps", "time": "ps"} class ConfigReader(base.SingleFrameReaderBase): @@ -47,13 +47,14 @@ class ConfigReader(base.SingleFrameReaderBase): coordinates, velocities, and forces are no longer stored in 'F' memory layout, instead now using the numpy default of 'C'. """ - format = 'CONFIG' + + format = "CONFIG" units = _DLPOLY_UNITS def _read_first_frame(self): unitcell = np.zeros((3, 3), dtype=np.float32) - with open(self.filename, 'r') as inf: + with open(self.filename, "r") as inf: self.title = inf.readline().strip() levcfg, imcon, megatm = np.int64(inf.readline().split()[:3]) if not imcon == 0: @@ -113,10 +114,9 @@ def _read_first_frame(self): if has_forces: forces = forces[order] - ts = self.ts = self._Timestep(self.n_atoms, - velocities=has_vels, - forces=has_forces, - **self._ts_kwargs) + ts = self.ts = self._Timestep( + self.n_atoms, velocities=has_vels, forces=has_forces, **self._ts_kwargs + ) ts._pos = coords if has_vels: ts._velocities = velocities @@ -133,7 +133,8 @@ class HistoryReader(base.ReaderBase): .. versionadded:: 0.11.0 """ - format = 'HISTORY' + + format = "HISTORY" units = _DLPOLY_UNITS @store_init_arguments @@ -142,7 +143,7 @@ def __init__(self, filename, **kwargs): self._cache = {} # "private" file handle - self._file = util.anyopen(self.filename, 'r') + self._file = util.anyopen(self.filename, "r") self.title = self._file.readline().strip() header = np.int64(self._file.readline().split()[:3]) self._levcfg, self._imcon, self.n_atoms = header @@ -157,10 +158,12 @@ def __init__(self, filename, **kwargs): self._has_cell = False self._file.seek(rwnd) - self.ts = self._Timestep(self.n_atoms, - velocities=self._has_vels, - forces=self._has_forces, - **self._ts_kwargs) + self.ts = self._Timestep( + self.n_atoms, + velocities=self._has_vels, + forces=self._has_forces, + **self._ts_kwargs + ) self._read_next_timestep() def _read_next_timestep(self, ts=None): @@ -168,7 +171,7 @@ def _read_next_timestep(self, ts=None): ts = self.ts line = self._file.readline() # timestep line - if not line.startswith('timestep'): + if not line.startswith("timestep"): raise IOError if self._has_cell: @@ -176,7 +179,7 @@ def _read_next_timestep(self, ts=None): unitcell[0] = self._file.readline().split() unitcell[1] = self._file.readline().split() unitcell[2] = self._file.readline().split() - ts.dimensions = core.triclinic_box(*unitcell) + ts.dimensions = core.triclinic_box(*unitcell) # If ids are given, put them in here # and later sort by them @@ -220,17 +223,17 @@ def _read_frame(self, frame): return self._read_next_timestep() @property - @cached('n_frames') + @cached("n_frames") def n_frames(self): # Second line is traj_key, imcom, n_atoms, n_frames, n_records offsets = [] - with open(self.filename, 'r') as f: + with open(self.filename, "r") as f: f.readline() f.readline() position = f.tell() line = f.readline() - while line.startswith('timestep'): + while line.startswith("timestep"): offsets.append(position) if self._has_cell: f.readline() @@ -251,7 +254,7 @@ def n_frames(self): def _reopen(self): self.close() - self._file = open(self.filename, 'r') + self._file = open(self.filename, "r") self._file.readline() # header is 2 lines self._file.readline() self.ts.frame = -1 diff --git a/package/MDAnalysis/coordinates/DMS.py b/package/MDAnalysis/coordinates/DMS.py index 04367f438d..55df8a1a1c 100644 --- a/package/MDAnalysis/coordinates/DMS.py +++ b/package/MDAnalysis/coordinates/DMS.py @@ -106,16 +106,12 @@ def dict_factory(cursor, row): ) self.ts.frame = 0 # 0-based frame number - self.ts.dimensions = triclinic_box( - unitcell["x"], unitcell["y"], unitcell["z"] - ) + self.ts.dimensions = triclinic_box(unitcell["x"], unitcell["y"], unitcell["z"]) if self.convert_units: self.convert_pos_from_native(self.ts._pos) # in-place ! if self.ts.dimensions is not None: - self.convert_pos_from_native( - self.ts.dimensions[:3] - ) # in-place ! + self.convert_pos_from_native(self.ts.dimensions[:3]) # in-place ! if self.ts.has_velocities: # converts nm/ps to A/ps units self.convert_velocities_from_native(self.ts._velocities) diff --git a/package/MDAnalysis/coordinates/FHIAIMS.py b/package/MDAnalysis/coordinates/FHIAIMS.py index 3aff6d97f5..48973e2963 100644 --- a/package/MDAnalysis/coordinates/FHIAIMS.py +++ b/package/MDAnalysis/coordinates/FHIAIMS.py @@ -191,9 +191,7 @@ def _read_first_frame(self): if len(lattice_vectors) > 0: ts.dimensions = triclinic_box(*lattice_vectors) - ts.positions[relative] = np.matmul( - ts.positions[relative], lattice_vectors - ) + ts.positions[relative] = np.matmul(ts.positions[relative], lattice_vectors) if len(velocities) > 0: ts.velocities = velocities @@ -321,9 +319,7 @@ def _write_next_frame(self, obj): # all attributes could be infinite cycles! for atom_index, name in zip(range(ag.n_atoms), names): output_fhiaims.write( - self.fmt["xyz"].format( - pos=positions[atom_index], name=name - ) + self.fmt["xyz"].format(pos=positions[atom_index], name=name) ) if has_velocities: output_fhiaims.write( diff --git a/package/MDAnalysis/coordinates/GMS.py b/package/MDAnalysis/coordinates/GMS.py index 6db412461d..b264146d22 100644 --- a/package/MDAnalysis/coordinates/GMS.py +++ b/package/MDAnalysis/coordinates/GMS.py @@ -75,7 +75,7 @@ class GMSReader(base.ReaderBase): format = "GMS" # these are assumed! - units = {'time': 'ps', 'length': 'Angstrom'} + units = {"time": "ps", "length": "Angstrom"} @store_init_arguments def __init__(self, outfilename, **kwargs): @@ -91,12 +91,12 @@ def __init__(self, outfilename, **kwargs): self._n_frames = None self._runtyp = None - self.ts = self._Timestep(0) # need for properties initial calculations + self.ts = self._Timestep(0) # need for properties initial calculations # update runtyp property self.runtyp - if not self.runtyp in ['optimize', 'surface']: - raise AttributeError('Wrong RUNTYP= '+self.runtyp) + if not self.runtyp in ["optimize", "surface"]: + raise AttributeError("Wrong RUNTYP= " + self.runtyp) self.ts = self._Timestep(self.n_atoms, **self._ts_kwargs) # update n_frames property @@ -108,7 +108,7 @@ def __init__(self, outfilename, **kwargs): @property def runtyp(self): """RUNTYP property of the GAMESS run""" - if self._runtyp is not None: # return cached value + if self._runtyp is not None: # return cached value return self._runtyp try: self._runtyp = self._determine_runtyp() @@ -120,7 +120,7 @@ def runtyp(self): def _determine_runtyp(self): with util.openany(self.filename) as out: for line in out: - m = re.match(r'^.*RUNTYP=([A-Z]+)\s+.*', line) + m = re.match(r"^.*RUNTYP=([A-Z]+)\s+.*", line) if m is not None: res = m.group(1).lower() break @@ -130,7 +130,7 @@ def _determine_runtyp(self): @property def n_atoms(self): """number of atoms in a frame""" - if self._n_atoms is not None: # return cached value + if self._n_atoms is not None: # return cached value return self._n_atoms try: self._n_atoms = self._read_out_natoms() @@ -142,7 +142,7 @@ def n_atoms(self): def _read_out_natoms(self): with util.openany(self.filename) as out: for line in out: - m = re.match(r'\s*TOTAL NUMBER OF ATOMS\s*=\s*([0-9]+)\s*',line) + m = re.match(r"\s*TOTAL NUMBER OF ATOMS\s*=\s*([0-9]+)\s*", line) if m is not None: res = int(m.group(1)) break @@ -151,7 +151,7 @@ def _read_out_natoms(self): @property def n_frames(self): - if self._n_frames is not None: # return cached value + if self._n_frames is not None: # return cached value return self._n_frames try: self._n_frames = self._read_out_n_frames() @@ -161,15 +161,15 @@ def n_frames(self): return self._n_frames def _read_out_n_frames(self): - if self.runtyp == 'optimize': - trigger = re.compile(b'^.NSERCH=.*') - elif self.runtyp == 'surface': - trigger = re.compile(b'^.COORD 1=.*') + if self.runtyp == "optimize": + trigger = re.compile(b"^.NSERCH=.*") + elif self.runtyp == "surface": + trigger = re.compile(b"^.COORD 1=.*") self._offsets = offsets = [] - with util.openany(self.filename, 'rb') as out: + with util.openany(self.filename, "rb") as out: line = True - while not line == b'': # while not EOF + while not line == b"": # while not EOF line = out.readline() if re.match(trigger, line): offsets.append(out.tell() - len(line)) @@ -196,15 +196,16 @@ def _read_next_timestep(self, ts=None): counter = 0 for line in self.outfile: - if self.runtyp == 'optimize': - if (flag == 0) and (re.match(r'^.NSERCH=.*', line) is not None): + if self.runtyp == "optimize": + if (flag == 0) and (re.match(r"^.NSERCH=.*", line) is not None): flag = 1 continue - if (flag == 1) and (re.match(r'^ COORDINATES OF ALL ATOMS ARE ',\ - line) is not None): + if (flag == 1) and ( + re.match(r"^ COORDINATES OF ALL ATOMS ARE ", line) is not None + ): flag = 2 continue - if (flag == 2) and (re.match(r'^\s*-+\s*', line) is not None): + if (flag == 2) and (re.match(r"^\s*-+\s*", line) is not None): flag = 3 continue if flag == 3 and counter < self.n_atoms: @@ -214,13 +215,16 @@ def _read_next_timestep(self, ts=None): z.append(float(words[4])) counter += 1 - elif self.runtyp == 'surface': - if (flag == 0) and (re.match(\ - r'^.COORD 1=\s*([-]?[0-9]+\.[0-9]+).*', line) is not None): + elif self.runtyp == "surface": + if (flag == 0) and ( + re.match(r"^.COORD 1=\s*([-]?[0-9]+\.[0-9]+).*", line) is not None + ): flag = 1 continue - if (flag == 1) and (re.match(\ - r'^\s*HAS ENERGY VALUE\s*([-]?[0-9]+\.[0-9]+)\s*', line) is not None): + if (flag == 1) and ( + re.match(r"^\s*HAS ENERGY VALUE\s*([-]?[0-9]+\.[0-9]+)\s*", line) + is not None + ): flag = 3 continue if flag == 3 and counter < self.n_atoms: @@ -232,10 +236,12 @@ def _read_next_timestep(self, ts=None): # stop when the cursor has reached the end of that block if counter == self._n_atoms: - ts._x[:] = x # more efficient to do it this way to avoid re-creating the numpy arrays + ts._x[:] = ( + x # more efficient to do it this way to avoid re-creating the numpy arrays + ) ts._y[:] = y ts._z[:] = z - #print ts.frame + # print ts.frame ts.frame += 1 return ts @@ -247,10 +253,10 @@ def _reopen(self): def open_trajectory(self): if self.outfile is not None: - raise IOError(errno.EALREADY, 'GMS file already opened', self.filename) + raise IOError(errno.EALREADY, "GMS file already opened", self.filename) if not os.path.exists(self.filename): # must check; otherwise might segmentation fault - raise IOError(errno.ENOENT, 'GMS file not found', self.filename) + raise IOError(errno.ENOENT, "GMS file not found", self.filename) self.outfile = util.anyopen(self.filename) diff --git a/package/MDAnalysis/coordinates/GRO.py b/package/MDAnalysis/coordinates/GRO.py index f7eed70400..bd03d74cbe 100644 --- a/package/MDAnalysis/coordinates/GRO.py +++ b/package/MDAnalysis/coordinates/GRO.py @@ -186,13 +186,11 @@ def _read_first_frame(self): first_atomline = grofile.readline() cs = first_atomline[25:].find(".") + 1 ts._pos[0] = [ - first_atomline[20 + cs * i : 20 + cs * (i + 1)] - for i in range(3) + first_atomline[20 + cs * i : 20 + cs * (i + 1)] for i in range(3) ] try: velocities[0] = [ - first_atomline[20 + cs * i : 20 + cs * (i + 1)] - for i in range(3, 6) + first_atomline[20 + cs * i : 20 + cs * (i + 1)] for i in range(3, 6) ] except ValueError: # Remember that we got this error @@ -206,18 +204,13 @@ def _read_first_frame(self): unitcell = np.float32(line.split()) except ValueError: # Try to parse floats with 5 digits if no spaces between values... - unitcell = np.float32( - re.findall(r"(\d+\.\d{5})", line) - ) + unitcell = np.float32(re.findall(r"(\d+\.\d{5})", line)) break - ts._pos[pos] = [ - line[20 + cs * i : 20 + cs * (i + 1)] for i in range(3) - ] + ts._pos[pos] = [line[20 + cs * i : 20 + cs * (i + 1)] for i in range(3)] try: velocities[pos] = [ - line[20 + cs * i : 20 + cs * (i + 1)] - for i in range(3, 6) + line[20 + cs * i : 20 + cs * (i + 1)] for i in range(3, 6) ] except ValueError: # Remember that we got this error @@ -227,8 +220,7 @@ def _read_first_frame(self): ts.velocities = velocities if missed_vel: warnings.warn( - "Not all velocities were present. " - "Unset velocities set to zero." + "Not all velocities were present. " "Unset velocities set to zero." ) self.ts.frame = 0 # 0-based frame number @@ -255,9 +247,7 @@ def _read_first_frame(self): if self.convert_units: self.convert_pos_from_native(self.ts._pos) # in-place ! if self.ts.dimensions is not None: - self.convert_pos_from_native( - self.ts.dimensions[:3] - ) # in-place! + self.convert_pos_from_native(self.ts.dimensions[:3]) # in-place! if self.ts.has_velocities: # converts nm/ps to A/ps units self.convert_velocities_from_native(self.ts._velocities) @@ -328,9 +318,7 @@ class GROWriter(base.WriterBase): "box_orthorhombic": "{box[0]:10.5f} {box[1]:9.5f} {box[2]:9.5f}\n", "box_triclinic": "{box[0]:10.5f} {box[4]:9.5f} {box[8]:9.5f} {box[1]:9.5f} {box[2]:9.5f} {box[3]:9.5f} {box[5]:9.5f} {box[6]:9.5f} {box[7]:9.5f}\n", } - fmt["xyz_v"] = ( - fmt["xyz"][:-1] + "{vel[0]:8.4f}{vel[1]:8.4f}{vel[2]:8.4f}\n" - ) + fmt["xyz_v"] = fmt["xyz"][:-1] + "{vel[0]:8.4f}{vel[1]:8.4f}{vel[2]:8.4f}\n" def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): """Set up a GROWriter with a precision of 3 decimal places. @@ -369,9 +357,7 @@ def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): self.n_atoms = n_atoms self.reindex = kwargs.pop("reindex", True) - self.convert_units = ( - convert_units # convert length and time to base units - ) + self.convert_units = convert_units # convert length and time to base units def write(self, obj): """Write selection at current trajectory frame to file. @@ -464,9 +450,7 @@ def write(self, obj): raise ValueError( "GRO files must have coordinate values between " "{0:.3f} and {1:.3f} nm: No file was written." - "".format( - self.gro_coor_limits["min"], self.gro_coor_limits["max"] - ) + "".format(self.gro_coor_limits["min"], self.gro_coor_limits["max"]) ) with util.openany(self.filename, "wt") as output_gro: @@ -480,9 +464,7 @@ def write(self, obj): for atom_index, resid, resname, name in zip( range(ag.n_atoms), resids, resnames, names ): - truncated_atom_index = util.ltruncate_int( - atom_indices[atom_index], 5 - ) + truncated_atom_index = util.ltruncate_int(atom_indices[atom_index], 5) truncated_resid = util.ltruncate_int(resid, 5) if has_velocities: output_gro.write( @@ -518,9 +500,7 @@ def write(self, obj): warnings.warn(wmsg) box = np.zeros(3) else: - box = self.convert_pos_to_native( - ag.dimensions[:3], inplace=False - ) + box = self.convert_pos_to_native(ag.dimensions[:3], inplace=False) # orthorhombic cell, only lengths along axes needed in gro output_gro.write(self.fmt["box_orthorhombic"].format(box=box)) else: @@ -529,7 +509,5 @@ def write(self, obj): except AttributeError: # for Timestep tri_dims = obj.triclinic_dimensions # full output - box = self.convert_pos_to_native( - tri_dims.flatten(), inplace=False - ) + box = self.convert_pos_to_native(tri_dims.flatten(), inplace=False) output_gro.write(self.fmt["box_triclinic"].format(box=box)) diff --git a/package/MDAnalysis/coordinates/H5MD.py b/package/MDAnalysis/coordinates/H5MD.py index d92828687f..39b8301bd3 100644 --- a/package/MDAnalysis/coordinates/H5MD.py +++ b/package/MDAnalysis/coordinates/H5MD.py @@ -215,6 +215,7 @@ from ..exceptions import NoDataError from ..due import due, Doi from MDAnalysis.lib.util import store_init_arguments + try: import h5py except ImportError: @@ -225,6 +226,7 @@ class MockH5pyFile: pass + h5py = types.ModuleType("h5py") h5py.File = MockH5pyFile @@ -338,65 +340,66 @@ class H5MDReader(base.ReaderBase): """ - format = 'H5MD' + format = "H5MD" # units is defined as instance-level variable and set from the # H5MD file in __init__() below # This dictionary is used to translate H5MD units to MDAnalysis units. # (https://nongnu.org/h5md/modules/units.html) _unit_translation = { - 'time': { - 'ps': 'ps', - 'fs': 'fs', - 'ns': 'ns', - 'second': 's', - 'sec': 's', - 's': 's', - 'AKMA': 'AKMA', + "time": { + "ps": "ps", + "fs": "fs", + "ns": "ns", + "second": "s", + "sec": "s", + "s": "s", + "AKMA": "AKMA", }, - 'length': { - 'Angstrom': 'Angstrom', - 'angstrom': 'Angstrom', - 'A': 'Angstrom', - 'nm': 'nm', - 'pm': 'pm', - 'fm': 'fm', + "length": { + "Angstrom": "Angstrom", + "angstrom": "Angstrom", + "A": "Angstrom", + "nm": "nm", + "pm": "pm", + "fm": "fm", }, - 'velocity': { - 'Angstrom ps-1': 'Angstrom/ps', - 'A ps-1': 'Angstrom/ps', - 'Angstrom fs-1': 'Angstrom/fs', - 'A fs-1': 'Angstrom/fs', - 'Angstrom AKMA-1': 'Angstrom/AKMA', - 'A AKMA-1': 'Angstrom/AKMA', - 'nm ps-1': 'nm/ps', - 'nm ns-1': 'nm/ns', - 'pm ps-1': 'pm/ps', - 'm s-1': 'm/s' + "velocity": { + "Angstrom ps-1": "Angstrom/ps", + "A ps-1": "Angstrom/ps", + "Angstrom fs-1": "Angstrom/fs", + "A fs-1": "Angstrom/fs", + "Angstrom AKMA-1": "Angstrom/AKMA", + "A AKMA-1": "Angstrom/AKMA", + "nm ps-1": "nm/ps", + "nm ns-1": "nm/ns", + "pm ps-1": "pm/ps", + "m s-1": "m/s", + }, + "force": { + "kJ mol-1 Angstrom-1": "kJ/(mol*Angstrom)", + "kJ mol-1 nm-1": "kJ/(mol*nm)", + "Newton": "Newton", + "N": "N", + "J m-1": "J/m", + "kcal mol-1 Angstrom-1": "kcal/(mol*Angstrom)", + "kcal mol-1 A-1": "kcal/(mol*Angstrom)", }, - 'force': { - 'kJ mol-1 Angstrom-1': 'kJ/(mol*Angstrom)', - 'kJ mol-1 nm-1': 'kJ/(mol*nm)', - 'Newton': 'Newton', - 'N': 'N', - 'J m-1': 'J/m', - 'kcal mol-1 Angstrom-1': 'kcal/(mol*Angstrom)', - 'kcal mol-1 A-1': 'kcal/(mol*Angstrom)' - } } - @due.dcite(Doi("10.25080/majora-1b6fd038-005"), - description="MDAnalysis trajectory reader/writer of the H5MD" - "format", path=__name__) - @due.dcite(Doi("10.1016/j.cpc.2014.01.018"), - description="Specifications of the H5MD standard", - path=__name__, version='1.1') + @due.dcite( + Doi("10.25080/majora-1b6fd038-005"), + description="MDAnalysis trajectory reader/writer of the H5MD" "format", + path=__name__, + ) + @due.dcite( + Doi("10.1016/j.cpc.2014.01.018"), + description="Specifications of the H5MD standard", + path=__name__, + version="1.1", + ) @store_init_arguments - def __init__(self, filename, - convert_units=True, - driver=None, - comm=None, - **kwargs): + def __init__(self, filename, convert_units=True, driver=None, comm=None, **kwargs): """ Parameters ---------- @@ -442,43 +445,49 @@ def __init__(self, filename, # opened with parallel h5py/hdf5 enabled self._driver = driver self._comm = comm - if (self._comm is not None) and (self._driver != 'mpio'): - raise ValueError("If MPI communicator object is used to open" - " h5md file, ``driver='mpio'`` must be passed.") + if (self._comm is not None) and (self._driver != "mpio"): + raise ValueError( + "If MPI communicator object is used to open" + " h5md file, ``driver='mpio'`` must be passed." + ) self.open_trajectory() - if self._particle_group['box'].attrs['dimension'] != 3: - raise ValueError("MDAnalysis only supports 3-dimensional" - " simulation boxes") + if self._particle_group["box"].attrs["dimension"] != 3: + raise ValueError( + "MDAnalysis only supports 3-dimensional" " simulation boxes" + ) # _has dictionary used for checking whether h5md file has # 'position', 'velocity', or 'force' groups in the file - self._has = {name: name in self._particle_group for - name in ('position', 'velocity', 'force')} + self._has = { + name: name in self._particle_group + for name in ("position", "velocity", "force") + } # Gets some info about what settings the datasets were created with # from first available group for name, value in self._has.items(): if value: - dset = self._particle_group[f'{name}/value'] + dset = self._particle_group[f"{name}/value"] self.n_atoms = dset.shape[1] self.compression = dset.compression self.compression_opts = dset.compression_opts break else: - raise NoDataError("Provide at least a position, velocity" - " or force group in the h5md file.") - - self.ts = self._Timestep(self.n_atoms, - positions=self.has_positions, - velocities=self.has_velocities, - forces=self.has_forces, - **self._ts_kwargs) - - self.units = {'time': None, - 'length': None, - 'velocity': None, - 'force': None} + raise NoDataError( + "Provide at least a position, velocity" + " or force group in the h5md file." + ) + + self.ts = self._Timestep( + self.n_atoms, + positions=self.has_positions, + velocities=self.has_velocities, + forces=self.has_forces, + **self._ts_kwargs, + ) + + self.units = {"time": None, "length": None, "velocity": None, "force": None} self._set_translated_units() # fills units dictionary self._read_next_timestep() @@ -487,11 +496,12 @@ def _set_translated_units(self): and fills units dictionary""" # need this dictionary to associate 'position': 'length' - _group_unit_dict = {'time': 'time', - 'position': 'length', - 'velocity': 'velocity', - 'force': 'force' - } + _group_unit_dict = { + "time": "time", + "position": "length", + "velocity": "velocity", + "force": "force", + } for group, unit in _group_unit_dict.items(): self._translate_h5md_units(group, unit) @@ -505,47 +515,52 @@ def _translate_h5md_units(self, group, unit): # doing time unit separately because time has to fish for # first available parent group - either position, velocity, or force - if unit == 'time': + if unit == "time": for name, value in self._has.items(): if value: - if 'unit' in self._particle_group[name]['time'].attrs: + if "unit" in self._particle_group[name]["time"].attrs: try: - self.units['time'] = self._unit_translation[ - 'time'][self._particle_group[name][ - 'time'].attrs['unit']] + self.units["time"] = self._unit_translation["time"][ + self._particle_group[name]["time"].attrs["unit"] + ] break except KeyError: - raise RuntimeError(errmsg.format( - unit, self._particle_group[ - name]['time'].attrs['unit']) - ) from None + raise RuntimeError( + errmsg.format( + unit, + self._particle_group[name]["time"].attrs["unit"], + ) + ) from None else: if self._has[group]: - if 'unit' in self._particle_group[group]['value'].attrs: + if "unit" in self._particle_group[group]["value"].attrs: try: self.units[unit] = self._unit_translation[unit][ - self._particle_group[group]['value'].attrs['unit']] + self._particle_group[group]["value"].attrs["unit"] + ] except KeyError: - raise RuntimeError(errmsg.format( - unit, self._particle_group[group][ - 'value'].attrs['unit']) - ) from None + raise RuntimeError( + errmsg.format( + unit, self._particle_group[group]["value"].attrs["unit"] + ) + ) from None # if position group is not provided, can still get 'length' unit # from unitcell box - if (not self._has['position']) and ('edges' in self._particle_group['box']): - if 'unit' in self._particle_group['box/edges/value'].attrs: + if (not self._has["position"]) and ("edges" in self._particle_group["box"]): + if "unit" in self._particle_group["box/edges/value"].attrs: try: - self.units['length'] = self._unit_translation[ - 'length'][self._particle_group[ - 'box/edges/value' - ].attrs['unit']] + self.units["length"] = self._unit_translation["length"][ + self._particle_group["box/edges/value"].attrs["unit"] + ] except KeyError: - raise RuntimeError(errmsg.format(unit, - self._particle_group[ - 'box/edges/value'].attrs[ - 'unit'])) from None + raise RuntimeError( + errmsg.format( + unit, + self._particle_group["box/edges/value"].attrs["unit"], + ) + ) from None def _check_units(self, group, unit): """Raises error if no units are provided from H5MD file @@ -558,8 +573,8 @@ def _check_units(self, group, unit): " set to ``True``. MDAnalysis sets ``convert_units=True`` by default." " Set ``convert_units=False`` to load Universe without units." - if unit == 'time': - if self.units['time'] is None: + if unit == "time": + if self.units["time"] is None: raise ValueError(errmsg) else: @@ -576,16 +591,18 @@ def _format_hint(thing): @staticmethod def parse_n_atoms(filename): - with h5py.File(filename, 'r') as f: - for group in f['particles/trajectory']: - if group in ('position', 'velocity', 'force'): - n_atoms = f[f'particles/trajectory/{group}/value'].shape[1] + with h5py.File(filename, "r") as f: + for group in f["particles/trajectory"]: + if group in ("position", "velocity", "force"): + n_atoms = f[f"particles/trajectory/{group}/value"].shape[1] return n_atoms - raise NoDataError("Could not construct minimal topology from the " - "H5MD trajectory file, as it did not contain a " - "'position', 'velocity', or 'force' group. " - "You must include a topology file.") + raise NoDataError( + "Could not construct minimal topology from the " + "H5MD trajectory file, as it did not contain a " + "'position', 'velocity', or 'force' group. " + "You must include a topology file." + ) def open_trajectory(self): """opens the trajectory file using h5py library""" @@ -596,38 +613,41 @@ def open_trajectory(self): else: if self._comm is not None: # can only pass comm argument to h5py.File if driver='mpio' - assert self._driver == 'mpio' - self._file = H5PYPicklable(name=self.filename, # pragma: no cover - mode='r', - driver=self._driver, - comm=self._comm) + assert self._driver == "mpio" + self._file = H5PYPicklable( + name=self.filename, # pragma: no cover + mode="r", + driver=self._driver, + comm=self._comm, + ) else: - self._file = H5PYPicklable(name=self.filename, - mode='r', - driver=self._driver) + self._file = H5PYPicklable( + name=self.filename, mode="r", driver=self._driver + ) # pulls first key out of 'particles' # allows for arbitrary name of group1 in 'particles' - self._particle_group = self._file['particles'][ - list(self._file['particles'])[0]] + self._particle_group = self._file["particles"][list(self._file["particles"])[0]] @property def n_frames(self): """number of frames in trajectory""" for name, value in self._has.items(): if value: - return self._particle_group[name]['value'].shape[0] + return self._particle_group[name]["value"].shape[0] def _read_frame(self, frame): """reads data from h5md file and copies to current timestep""" try: for name, value in self._has.items(): if value: - _ = self._particle_group[name]['step'][frame] + _ = self._particle_group[name]["step"][frame] break else: - raise NoDataError("Provide at least a position, velocity" - " or force group in the h5md file.") + raise NoDataError( + "Provide at least a position, velocity" + " or force group in the h5md file." + ) except (ValueError, IndexError): raise IOError from None @@ -659,12 +679,12 @@ def _read_frame(self, frame): # set the timestep positions, velocities, and forces with # current frame dataset - if self._has['position']: - self._read_dataset_into_ts('position', ts.positions) - if self._has['velocity']: - self._read_dataset_into_ts('velocity', ts.velocities) - if self._has['force']: - self._read_dataset_into_ts('force', ts.forces) + if self._has["position"]: + self._read_dataset_into_ts("position", ts.positions) + if self._has["velocity"]: + self._read_dataset_into_ts("velocity", ts.velocities) + if self._has["force"]: + self._read_dataset_into_ts("force", ts.forces) if self.convert_units: self._convert_units() @@ -679,9 +699,9 @@ def _copy_to_data(self): try: # if has value as subkey read directly into data if "value" in self._file["observables"][key]: - self.ts.data[key] = self._file["observables"][key][ - "value" - ][self._frame] + self.ts.data[key] = self._file["observables"][key]["value"][ + self._frame + ] # if value is not a subkey, read dict of subkeys else: for subkey in self._file["observables"][key].keys(): @@ -699,33 +719,35 @@ def _copy_to_data(self): # pulls 'time' and 'step' out of first available parent group for name, value in self._has.items(): if value: - if 'time' in self._particle_group[name]: - self.ts.time = self._particle_group[name][ - 'time'][self._frame] + if "time" in self._particle_group[name]: + self.ts.time = self._particle_group[name]["time"][self._frame] break for name, value in self._has.items(): if value: - if 'step' in self._particle_group[name]: - self.ts.data['step'] = self._particle_group[name][ - 'step'][self._frame] + if "step" in self._particle_group[name]: + self.ts.data["step"] = self._particle_group[name]["step"][ + self._frame + ] break def _read_dataset_into_ts(self, dataset, attribute): """reads position, velocity, or force dataset array at current frame into corresponding ts attribute""" - n_atoms_now = self._particle_group[f'{dataset}/value'][ - self._frame].shape[0] + n_atoms_now = self._particle_group[f"{dataset}/value"][self._frame].shape[0] if n_atoms_now != self.n_atoms: - raise ValueError(f"Frame {self._frame} of the {dataset} dataset" - f" has {n_atoms_now} atoms but the initial frame" - " of either the postion, velocity, or force" - f" dataset had {self.n_atoms} atoms." - " MDAnalysis is unable to deal" - " with variable topology!") - - self._particle_group[f'{dataset}/value'].read_direct( - attribute, source_sel=np.s_[self._frame, :]) + raise ValueError( + f"Frame {self._frame} of the {dataset} dataset" + f" has {n_atoms_now} atoms but the initial frame" + " of either the postion, velocity, or force" + f" dataset had {self.n_atoms} atoms." + " MDAnalysis is unable to deal" + " with variable topology!" + ) + + self._particle_group[f"{dataset}/value"].read_direct( + attribute, source_sel=np.s_[self._frame, :] + ) def _convert_units(self): """converts time, position, velocity, and force values if they @@ -736,16 +758,16 @@ def _convert_units(self): self.ts.time = self.convert_time_from_native(self.ts.time) - if 'edges' in self._particle_group['box'] and self.ts.dimensions is not None: + if "edges" in self._particle_group["box"] and self.ts.dimensions is not None: self.convert_pos_from_native(self.ts.dimensions[:3]) - if self._has['position']: + if self._has["position"]: self.convert_pos_from_native(self.ts.positions) - if self._has['velocity']: + if self._has["velocity"]: self.convert_velocities_from_native(self.ts.velocities) - if self._has['force']: + if self._has["force"]: self.convert_forces_from_native(self.ts.forces) def _read_next_timestep(self): @@ -802,50 +824,49 @@ def Writer(self, filename, n_atoms=None, **kwargs): """ if n_atoms is None: n_atoms = self.n_atoms - kwargs.setdefault('driver', self._driver) - kwargs.setdefault('compression', self.compression) - kwargs.setdefault('compression_opts', self.compression_opts) - kwargs.setdefault('positions', self.has_positions) - kwargs.setdefault('velocities', self.has_velocities) - kwargs.setdefault('forces', self.has_forces) + kwargs.setdefault("driver", self._driver) + kwargs.setdefault("compression", self.compression) + kwargs.setdefault("compression_opts", self.compression_opts) + kwargs.setdefault("positions", self.has_positions) + kwargs.setdefault("velocities", self.has_velocities) + kwargs.setdefault("forces", self.has_forces) return H5MDWriter(filename, n_atoms, **kwargs) @property def has_positions(self): """``True`` if 'position' group is in trajectory.""" - return self._has['position'] + return self._has["position"] @has_positions.setter def has_positions(self, value: bool): - self._has['position'] = value + self._has["position"] = value @property def has_velocities(self): """``True`` if 'velocity' group is in trajectory.""" - return self._has['velocity'] + return self._has["velocity"] @has_velocities.setter def has_velocities(self, value: bool): - self._has['velocity'] = value + self._has["velocity"] = value @property def has_forces(self): """``True`` if 'force' group is in trajectory.""" - return self._has['force'] + return self._has["force"] @has_forces.setter def has_forces(self, value: bool): - self._has['force'] = value + self._has["force"] = value def __getstate__(self): state = self.__dict__.copy() - del state['_particle_group'] + del state["_particle_group"] return state def __setstate__(self, state): self.__dict__ = state - self._particle_group = self._file['particles'][ - list(self._file['particles'])[0]] + self._particle_group = self._file["particles"][list(self._file["particles"])[0]] class H5MDWriter(base.WriterBase): @@ -1025,11 +1046,11 @@ class H5MDWriter(base.WriterBase): """ - format = 'H5MD' + format = "H5MD" multiframe = True #: These variables are not written from :attr:`Timestep.data` #: dictionary to the observables group in the H5MD file - data_blacklist = ['step', 'time', 'dt'] + data_blacklist = ["step", "time", "dt"] #: currently written version of the file format H5MD_VERSION = (1, 1) @@ -1037,54 +1058,80 @@ class H5MDWriter(base.WriterBase): # This dictionary is used to translate MDAnalysis units to H5MD units. # (https://nongnu.org/h5md/modules/units.html) _unit_translation_dict = { - 'time': { - 'ps': 'ps', - 'fs': 'fs', - 'ns': 'ns', - 'second': 's', - 'sec': 's', - 's': 's', - 'AKMA': 'AKMA'}, - 'length': { - 'Angstrom': 'Angstrom', - 'angstrom': 'Angstrom', - 'A': 'Angstrom', - 'nm': 'nm', - 'pm': 'pm', - 'fm': 'fm'}, - 'velocity': { - 'Angstrom/ps': 'Angstrom ps-1', - 'A/ps': 'Angstrom ps-1', - 'Angstrom/fs': 'Angstrom fs-1', - 'A/fs': 'Angstrom fs-1', - 'Angstrom/AKMA': 'Angstrom AKMA-1', - 'A/AKMA': 'Angstrom AKMA-1', - 'nm/ps': 'nm ps-1', - 'nm/ns': 'nm ns-1', - 'pm/ps': 'pm ps-1', - 'm/s': 'm s-1'}, - 'force': { - 'kJ/(mol*Angstrom)': 'kJ mol-1 Angstrom-1', - 'kJ/(mol*nm)': 'kJ mol-1 nm-1', - 'Newton': 'Newton', - 'N': 'N', - 'J/m': 'J m-1', - 'kcal/(mol*Angstrom)': 'kcal mol-1 Angstrom-1', - 'kcal/(mol*A)': 'kcal mol-1 Angstrom-1'}} - - @due.dcite(Doi("10.25080/majora-1b6fd038-005"), - description="MDAnalysis trajectory reader/writer of the H5MD" - "format", path=__name__) - @due.dcite(Doi("10.1016/j.cpc.2014.01.018"), - description="Specifications of the H5MD standard", - path=__name__, version='1.1') - def __init__(self, filename, n_atoms, n_frames=None, driver=None, - convert_units=True, chunks=None, compression=None, - compression_opts=None, positions=True, velocities=True, - forces=True, timeunit=None, lengthunit=None, - velocityunit=None, forceunit=None, author='N/A', - author_email=None, creator='MDAnalysis', - creator_version=mda.__version__, **kwargs): + "time": { + "ps": "ps", + "fs": "fs", + "ns": "ns", + "second": "s", + "sec": "s", + "s": "s", + "AKMA": "AKMA", + }, + "length": { + "Angstrom": "Angstrom", + "angstrom": "Angstrom", + "A": "Angstrom", + "nm": "nm", + "pm": "pm", + "fm": "fm", + }, + "velocity": { + "Angstrom/ps": "Angstrom ps-1", + "A/ps": "Angstrom ps-1", + "Angstrom/fs": "Angstrom fs-1", + "A/fs": "Angstrom fs-1", + "Angstrom/AKMA": "Angstrom AKMA-1", + "A/AKMA": "Angstrom AKMA-1", + "nm/ps": "nm ps-1", + "nm/ns": "nm ns-1", + "pm/ps": "pm ps-1", + "m/s": "m s-1", + }, + "force": { + "kJ/(mol*Angstrom)": "kJ mol-1 Angstrom-1", + "kJ/(mol*nm)": "kJ mol-1 nm-1", + "Newton": "Newton", + "N": "N", + "J/m": "J m-1", + "kcal/(mol*Angstrom)": "kcal mol-1 Angstrom-1", + "kcal/(mol*A)": "kcal mol-1 Angstrom-1", + }, + } + + @due.dcite( + Doi("10.25080/majora-1b6fd038-005"), + description="MDAnalysis trajectory reader/writer of the H5MD" "format", + path=__name__, + ) + @due.dcite( + Doi("10.1016/j.cpc.2014.01.018"), + description="Specifications of the H5MD standard", + path=__name__, + version="1.1", + ) + def __init__( + self, + filename, + n_atoms, + n_frames=None, + driver=None, + convert_units=True, + chunks=None, + compression=None, + compression_opts=None, + positions=True, + velocities=True, + forces=True, + timeunit=None, + lengthunit=None, + velocityunit=None, + forceunit=None, + author="N/A", + author_email=None, + creator="MDAnalysis", + creator_version=mda.__version__, + **kwargs, + ): if not HAS_H5PY: raise RuntimeError("H5MDWriter: Please install h5py") @@ -1092,15 +1139,19 @@ def __init__(self, filename, n_atoms, n_frames=None, driver=None, if n_atoms == 0: raise ValueError("H5MDWriter: no atoms in output trajectory") self._driver = driver - if self._driver == 'mpio': - raise ValueError("H5MDWriter: parallel writing with MPI I/O " - "is not currently supported.") + if self._driver == "mpio": + raise ValueError( + "H5MDWriter: parallel writing with MPI I/O " + "is not currently supported." + ) self.n_atoms = n_atoms self.n_frames = n_frames self.chunks = (1, n_atoms, 3) if chunks is None else chunks if self.chunks is False and self.n_frames is None: - raise ValueError("H5MDWriter must know how many frames will be " - "written if ``chunks=False``.") + raise ValueError( + "H5MDWriter must know how many frames will be " + "written if ``chunks=False``." + ) self.contiguous = self.chunks is False and self.n_frames is not None self.compression = compression self.compression_opts = compression_opts @@ -1114,16 +1165,20 @@ def __init__(self, filename, n_atoms, n_frames=None, driver=None, self._write_positions = positions self._write_velocities = velocities self._write_forces = forces - if not any([self._write_positions, - self._write_velocities, - self._write_velocities]): - raise ValueError("At least one of positions, velocities, or " - "forces must be set to ``True``.") - - self._new_units = {'time': timeunit, - 'length': lengthunit, - 'velocity': velocityunit, - 'force': forceunit} + if not any( + [self._write_positions, self._write_velocities, self._write_velocities] + ): + raise ValueError( + "At least one of positions, velocities, or " + "forces must be set to ``True``." + ) + + self._new_units = { + "time": timeunit, + "length": lengthunit, + "velocity": velocityunit, + "force": forceunit, + } # Pull out various keywords to store metadata in 'h5md' group self.author = author @@ -1152,8 +1207,9 @@ def _write_next_frame(self, ag): raise TypeError(errmsg) from None if ts.n_atoms != self.n_atoms: - raise IOError("H5MDWriter: Timestep does not have" - " the correct number of atoms") + raise IOError( + "H5MDWriter: Timestep does not have" " the correct number of atoms" + ) # This should only be called once when first timestep is read. if self.h5md_file is None: @@ -1184,21 +1240,25 @@ def _determine_units(self, ag): for key, value in self._new_units.items(): if value is not None: if value not in self._unit_translation_dict[key]: - raise ValueError(f"{value} is not a unit recognized by" - " MDAnalysis. Allowed units are:" - f" {self._unit_translation_dict.keys()}" - " For more information on units, see" - " `MDAnalysis units`_.") + raise ValueError( + f"{value} is not a unit recognized by" + " MDAnalysis. Allowed units are:" + f" {self._unit_translation_dict.keys()}" + " For more information on units, see" + " `MDAnalysis units`_." + ) else: self.units[key] = self._new_units[key] if self.convert_units: # check if all units are None if not any(self.units.values()): - raise ValueError("The trajectory has no units, but " - "`convert_units` is set to ``True`` by " - "default in MDAnalysis. To write the file " - "with no units, set ``convert_units=False``.") + raise ValueError( + "The trajectory has no units, but " + "`convert_units` is set to ``True`` by " + "default in MDAnalysis. To write the file " + "with no units, set ``convert_units=False``." + ) def _open_file(self): """Opens file with `H5PY`_ library and fills in metadata from kwargs. @@ -1207,20 +1267,18 @@ def _open_file(self): """ - self.h5md_file = h5py.File(name=self.filename, - mode='w', - driver=self._driver) + self.h5md_file = h5py.File(name=self.filename, mode="w", driver=self._driver) # fill in H5MD metadata from kwargs - self.h5md_file.require_group('h5md') - self.h5md_file['h5md'].attrs['version'] = np.array(self.H5MD_VERSION) - self.h5md_file['h5md'].require_group('author') - self.h5md_file['h5md/author'].attrs['name'] = self.author + self.h5md_file.require_group("h5md") + self.h5md_file["h5md"].attrs["version"] = np.array(self.H5MD_VERSION) + self.h5md_file["h5md"].require_group("author") + self.h5md_file["h5md/author"].attrs["name"] = self.author if self.author_email is not None: - self.h5md_file['h5md/author'].attrs['email'] = self.author_email - self.h5md_file['h5md'].require_group('creator') - self.h5md_file['h5md/creator'].attrs['name'] = self.creator - self.h5md_file['h5md/creator'].attrs['version'] = self.creator_version + self.h5md_file["h5md/author"].attrs["email"] = self.author_email + self.h5md_file["h5md"].require_group("creator") + self.h5md_file["h5md/creator"].attrs["name"] = self.creator + self.h5md_file["h5md/creator"].attrs["version"] = self.creator_version def _initialize_hdf5_datasets(self, ts): """initializes all datasets that will be written to by @@ -1242,57 +1300,61 @@ def _initialize_hdf5_datasets(self, ts): # ask the parent file if it has positions, velocities, and forces # if prompted by the writer with the self._write_* attributes - self._has = {group: getattr(ts, f'has_{attr}') - if getattr(self, f'_write_{attr}') - else False for group, attr in zip( - ('position', 'velocity', 'force'), - ('positions', 'velocities', 'forces'))} + self._has = { + group: ( + getattr(ts, f"has_{attr}") if getattr(self, f"_write_{attr}") else False + ) + for group, attr in zip( + ("position", "velocity", "force"), ("positions", "velocities", "forces") + ) + } # initialize trajectory group - self.h5md_file.require_group('particles').require_group('trajectory') - self._traj = self.h5md_file['particles/trajectory'] + self.h5md_file.require_group("particles").require_group("trajectory") + self._traj = self.h5md_file["particles/trajectory"] self.data_keys = [ - key for key in ts.data.keys() if key not in self.data_blacklist] + key for key in ts.data.keys() if key not in self.data_blacklist + ] if self.data_keys: - self._obsv = self.h5md_file.require_group('observables') + self._obsv = self.h5md_file.require_group("observables") # box group is required for every group in 'particles' - self._traj.require_group('box') - self._traj['box'].attrs['dimension'] = 3 + self._traj.require_group("box") + self._traj["box"].attrs["dimension"] = 3 if ts.dimensions is not None and np.all(ts.dimensions > 0): - self._traj['box'].attrs['boundary'] = 3*['periodic'] - self._traj['box'].require_group('edges') - self._edges = self._traj.require_dataset('box/edges/value', - shape=(0, 3, 3), - maxshape=(None, 3, 3), - dtype=np.float32) - self._step = self._traj.require_dataset('box/edges/step', - shape=(0,), - maxshape=(None,), - dtype=np.int32) - self._time = self._traj.require_dataset('box/edges/time', - shape=(0,), - maxshape=(None,), - dtype=np.float32) - self._set_attr_unit(self._edges, 'length') - self._set_attr_unit(self._time, 'time') + self._traj["box"].attrs["boundary"] = 3 * ["periodic"] + self._traj["box"].require_group("edges") + self._edges = self._traj.require_dataset( + "box/edges/value", + shape=(0, 3, 3), + maxshape=(None, 3, 3), + dtype=np.float32, + ) + self._step = self._traj.require_dataset( + "box/edges/step", shape=(0,), maxshape=(None,), dtype=np.int32 + ) + self._time = self._traj.require_dataset( + "box/edges/time", shape=(0,), maxshape=(None,), dtype=np.float32 + ) + self._set_attr_unit(self._edges, "length") + self._set_attr_unit(self._time, "time") else: # if no box, boundary attr must be "none" according to H5MD - self._traj['box'].attrs['boundary'] = 3*['none'] + self._traj["box"].attrs["boundary"] = 3 * ["none"] self._create_step_and_time_datasets() if self.has_positions: - self._create_trajectory_dataset('position') - self._pos = self._traj['position/value'] - self._set_attr_unit(self._pos, 'length') + self._create_trajectory_dataset("position") + self._pos = self._traj["position/value"] + self._set_attr_unit(self._pos, "length") if self.has_velocities: - self._create_trajectory_dataset('velocity') - self._vel = self._traj['velocity/value'] - self._set_attr_unit(self._vel, 'velocity') + self._create_trajectory_dataset("velocity") + self._vel = self._traj["velocity/value"] + self._set_attr_unit(self._vel, "velocity") if self.has_forces: - self._create_trajectory_dataset('force') - self._force = self._traj['force/value'] - self._set_attr_unit(self._force, 'force') + self._create_trajectory_dataset("force") + self._force = self._traj["force/value"] + self._set_attr_unit(self._force, "force") # intialize observable datasets from ts.data dictionary that # are NOT in self.data_blacklist @@ -1321,15 +1383,13 @@ def _create_step_and_time_datasets(self): for group, value in self._has.items(): if value: - self._step = self._traj.require_dataset(f'{group}/step', - shape=(0,), - maxshape=(None,), - dtype=np.int32) - self._time = self._traj.require_dataset(f'{group}/time', - shape=(0,), - maxshape=(None,), - dtype=np.float32) - self._set_attr_unit(self._time, 'time') + self._step = self._traj.require_dataset( + f"{group}/step", shape=(0,), maxshape=(None,), dtype=np.int32 + ) + self._time = self._traj.require_dataset( + f"{group}/time", shape=(0,), maxshape=(None,), dtype=np.float32 + ) + self._set_attr_unit(self._time, "time") break def _create_trajectory_dataset(self, group): @@ -1346,17 +1406,19 @@ def _create_trajectory_dataset(self, group): chunks = None if self.contiguous else self.chunks self._traj.require_group(group) - self._traj.require_dataset(f'{group}/value', - shape=shape, - maxshape=maxshape, - dtype=np.float32, - chunks=chunks, - compression=self.compression, - compression_opts=self.compression_opts) - if 'step' not in self._traj[group]: - self._traj[f'{group}/step'] = self._step - if 'time' not in self._traj[group]: - self._traj[f'{group}/time'] = self._time + self._traj.require_dataset( + f"{group}/value", + shape=shape, + maxshape=maxshape, + dtype=np.float32, + chunks=chunks, + compression=self.compression, + compression_opts=self.compression_opts, + ) + if "step" not in self._traj[group]: + self._traj[f"{group}/step"] = self._step + if "time" not in self._traj[group]: + self._traj[f"{group}/time"] = self._time def _create_observables_dataset(self, group, data): """helper function to initialize a dataset for each observable""" @@ -1364,14 +1426,16 @@ def _create_observables_dataset(self, group, data): self._obsv.require_group(group) # guarantee ints and floats have a shape () data = np.asarray(data) - self._obsv.require_dataset(f'{group}/value', - shape=(0,) + data.shape, - maxshape=(None,) + data.shape, - dtype=data.dtype) - if 'step' not in self._obsv[group]: - self._obsv[f'{group}/step'] = self._step - if 'time' not in self._obsv[group]: - self._obsv[f'{group}/time'] = self._time + self._obsv.require_dataset( + f"{group}/value", + shape=(0,) + data.shape, + maxshape=(None,) + data.shape, + dtype=data.dtype, + ) + if "step" not in self._obsv[group]: + self._obsv[f"{group}/step"] = self._step + if "time" not in self._obsv[group]: + self._obsv[f"{group}/time"] = self._time def _set_attr_unit(self, dset, unit): """helper function to set a 'unit' attribute for an HDF5 dataset""" @@ -1379,7 +1443,7 @@ def _set_attr_unit(self, dset, unit): if self.units[unit] is None: return - dset.attrs['unit'] = self._unit_translation_dict[unit][self.units[unit]] + dset.attrs["unit"] = self._unit_translation_dict[unit][self.units[unit]] def _write_next_timestep(self, ts): """Write coordinates and unitcell information to H5MD file. @@ -1406,42 +1470,43 @@ def _write_next_timestep(self, ts): # sampled, therefore ts.data['step'] is the most appropriate value # to use. However, step is also necessary in H5MD to allow # temporal matching of the data, so ts.frame is used as an alternative - self._step.resize(self._step.shape[0]+1, axis=0) + self._step.resize(self._step.shape[0] + 1, axis=0) try: - self._step[i] = ts.data['step'] - except(KeyError): + self._step[i] = ts.data["step"] + except KeyError: self._step[i] = ts.frame - if len(self._step) > 1 and self._step[i] < self._step[i-1]: - raise ValueError("The H5MD standard dictates that the step " - "dataset must increase monotonically in value.") + if len(self._step) > 1 and self._step[i] < self._step[i - 1]: + raise ValueError( + "The H5MD standard dictates that the step " + "dataset must increase monotonically in value." + ) # the dataset.resize() method should work with any chunk shape - self._time.resize(self._time.shape[0]+1, axis=0) + self._time.resize(self._time.shape[0] + 1, axis=0) self._time[i] = ts.time - if 'edges' in self._traj['box']: - self._edges.resize(self._edges.shape[0]+1, axis=0) - self._edges.write_direct(ts.triclinic_dimensions, - dest_sel=np.s_[i, :]) + if "edges" in self._traj["box"]: + self._edges.resize(self._edges.shape[0] + 1, axis=0) + self._edges.write_direct(ts.triclinic_dimensions, dest_sel=np.s_[i, :]) # These datasets are not resized if n_frames was provided as an # argument, as they were initialized with their full size. if self.has_positions: if self.n_frames is None: - self._pos.resize(self._pos.shape[0]+1, axis=0) + self._pos.resize(self._pos.shape[0] + 1, axis=0) self._pos.write_direct(ts.positions, dest_sel=np.s_[i, :]) if self.has_velocities: if self.n_frames is None: - self._vel.resize(self._vel.shape[0]+1, axis=0) + self._vel.resize(self._vel.shape[0] + 1, axis=0) self._vel.write_direct(ts.velocities, dest_sel=np.s_[i, :]) if self.has_forces: if self.n_frames is None: - self._force.resize(self._force.shape[0]+1, axis=0) + self._force.resize(self._force.shape[0] + 1, axis=0) self._force.write_direct(ts.forces, dest_sel=np.s_[i, :]) if self.data_keys: for key in self.data_keys: - obs = self._obsv[f'{key}/value'] - obs.resize(obs.shape[0]+1, axis=0) + obs = self._obsv[f"{key}/value"] + obs.resize(obs.shape[0] + 1, axis=0) obs[i] = ts.data[key] if self.convert_units: @@ -1454,34 +1519,34 @@ def _convert_dataset_with_units(self, i): # Note: simply doing convert_pos_to_native(self._pos[-1]) does not # actually change the values in the dataset, so assignment required - if self.units['time'] is not None: + if self.units["time"] is not None: self._time[i] = self.convert_time_to_native(self._time[i]) - if self.units['length'] is not None: - if self._has['position']: + if self.units["length"] is not None: + if self._has["position"]: self._pos[i] = self.convert_pos_to_native(self._pos[i]) - if 'edges' in self._traj['box']: + if "edges" in self._traj["box"]: self._edges[i] = self.convert_pos_to_native(self._edges[i]) - if self._has['velocity']: - if self.units['velocity'] is not None: + if self._has["velocity"]: + if self.units["velocity"] is not None: self._vel[i] = self.convert_velocities_to_native(self._vel[i]) - if self._has['force']: - if self.units['force'] is not None: + if self._has["force"]: + if self.units["force"] is not None: self._force[i] = self.convert_forces_to_native(self._force[i]) @property def has_positions(self): """``True`` if writer is writing positions from Timestep.""" - return self._has['position'] + return self._has["position"] @property def has_velocities(self): """``True`` if writer is writing velocities from Timestep.""" - return self._has['velocity'] + return self._has["velocity"] @property def has_forces(self): """``True`` if writer is writing forces from Timestep.""" - return self._has['force'] + return self._has["force"] class H5PYPicklable(h5py.File): @@ -1540,18 +1605,16 @@ def __getstate__(self): # from self and pickle MPI.Comm object. Parallel driver is excluded # from test because h5py calls for an MPI configuration when driver is # 'mpio', so this will need to be patched in the test function. - if driver == 'mpio': # pragma: no cover - raise TypeError("Parallel pickling of `h5py.File` with" # pragma: no cover - " 'mpio' driver is currently not supported.") + if driver == "mpio": # pragma: no cover + raise TypeError( + "Parallel pickling of `h5py.File` with" # pragma: no cover + " 'mpio' driver is currently not supported." + ) - return {'name': self.filename, - 'mode': self.mode, - 'driver': driver} + return {"name": self.filename, "mode": self.mode, "driver": driver} def __setstate__(self, state): - self.__init__(name=state['name'], - mode=state['mode'], - driver=state['driver']) + self.__init__(name=state["name"], mode=state["mode"], driver=state["driver"]) def __getnewargs__(self): """Override the h5py getnewargs to skip its error message""" diff --git a/package/MDAnalysis/coordinates/LAMMPS.py b/package/MDAnalysis/coordinates/LAMMPS.py index a8584bb3f1..d0fc0115bc 100644 --- a/package/MDAnalysis/coordinates/LAMMPS.py +++ b/package/MDAnalysis/coordinates/LAMMPS.py @@ -221,9 +221,7 @@ def __init__(self, dcdfilename, **kwargs): ) ) except KeyError: - raise ValueError( - "LAMMPS DCDReader: unknown unit {0!r}".format(unit) - ) + raise ValueError("LAMMPS DCDReader: unknown unit {0!r}".format(unit)) super(DCDReader, self).__init__(dcdfilename, **kwargs) @@ -256,9 +254,7 @@ def _read_first_frame(self): if self.convert_units: self.convert_pos_from_native(self.ts._pos) # in-place ! try: - self.convert_velocities_from_native( - self.ts._velocities - ) # in-place ! + self.convert_velocities_from_native(self.ts._velocities) # in-place ! except AttributeError: pass @@ -333,9 +329,7 @@ def _write_atoms(self, atoms, data): moltags = data.get("molecule_tag", np.zeros(len(atoms), dtype=int)) if self.convert_units: - coordinates = self.convert_pos_to_native( - atoms.positions, inplace=False - ) + coordinates = self.convert_pos_to_native(atoms.positions, inplace=False) if has_charges: for index, moltag, atype, charge, coords in zip( @@ -343,26 +337,21 @@ def _write_atoms(self, atoms, data): ): x, y, z = coords self.f.write( - f"{index:d} {moltag:d} {atype:d} {charge:f}" - f" {x:f} {y:f} {z:f}\n" + f"{index:d} {moltag:d} {atype:d} {charge:f}" f" {x:f} {y:f} {z:f}\n" ) else: for index, moltag, atype, coords in zip( indices, moltags, types, coordinates ): x, y, z = coords - self.f.write( - f"{index:d} {moltag:d} {atype:d}" f" {x:f} {y:f} {z:f}\n" - ) + self.f.write(f"{index:d} {moltag:d} {atype:d}" f" {x:f} {y:f} {z:f}\n") def _write_velocities(self, atoms): self.f.write("\n") self.f.write("Velocities\n") self.f.write("\n") indices = atoms.indices + 1 - velocities = self.convert_velocities_to_native( - atoms.velocities, inplace=False - ) + velocities = self.convert_velocities_to_native(atoms.velocities, inplace=False) for index, vel in zip(indices, velocities): self.f.write( "{i:d} {x:f} {y:f} {z:f}\n".format( @@ -379,9 +368,7 @@ def _write_masses(self, atoms): for atype in range(1, max_type + 1): # search entire universe for mass info, not just writing selection masses = set( - atoms.universe.atoms.select_atoms( - "type {:d}".format(atype) - ).masses + atoms.universe.atoms.select_atoms("type {:d}".format(atype)).masses ) if len(masses) == 0: mass_dict[atype] = 1.0 @@ -474,10 +461,7 @@ def write(self, selection, frame=None): try: atoms.types.astype(np.int32) except ValueError: - errmsg = ( - "LAMMPS.DATAWriter: atom types must be convertible to " - "integers" - ) + errmsg = "LAMMPS.DATAWriter: atom types must be convertible to " "integers" raise ValueError(errmsg) from None try: @@ -502,24 +486,18 @@ def write(self, selection, frame=None): for btype, attr_name in attrs: features[btype] = atoms.__getattribute__(attr_name) - self.f.write( - "{:>12d} {}\n".format(len(features[btype]), attr_name) - ) + self.f.write("{:>12d} {}\n".format(len(features[btype]), attr_name)) features[btype] = features[btype].atomgroup_intersection( atoms, strict=True ) self.f.write("\n") self.f.write( - "{:>12d} atom types\n".format( - max(atoms.types.astype(np.int32)) - ) + "{:>12d} atom types\n".format(max(atoms.types.astype(np.int32))) ) for btype, attr in features.items(): - self.f.write( - "{:>12d} {} types\n".format(len(attr.types()), btype) - ) + self.f.write("{:>12d} {} types\n".format(len(attr.types()), btype)) self._write_dimensions(atoms.dimensions) @@ -825,9 +803,7 @@ def _read_next_timestep(self): try: # this will automatically select in order of priority # unscaled, scaled, unwrapped, scaled_unwrapped - self.lammps_coordinate_convention = list(convention_to_col_ix)[ - 0 - ] + self.lammps_coordinate_convention = list(convention_to_col_ix)[0] except IndexError: raise ValueError("No coordinate information detected") elif not self.lammps_coordinate_convention in convention_to_col_ix: @@ -855,9 +831,7 @@ def _read_next_timestep(self): "Some of the additional columns are not present " "in the file, they will be ignored" ) - additional_keys = [ - key for key in self._additional_columns if key in attrs - ] + additional_keys = [key for key in self._additional_columns if key in attrs] else: additional_keys = [] for key in additional_keys: @@ -868,9 +842,7 @@ def _read_next_timestep(self): fields = f.readline().split() if ids: indices[i] = fields[attr_to_col_ix["id"]] - coords = np.array( - [fields[dim] for dim in coord_cols], dtype=np.float32 - ) + coords = np.array([fields[dim] for dim in coord_cols], dtype=np.float32) if self._unwrap: images = coords[3:] @@ -887,9 +859,7 @@ def _read_next_timestep(self): # Collect additional cols for attribute_key in additional_keys: - ts.data[attribute_key][i] = fields[ - attr_to_col_ix[attribute_key] - ] + ts.data[attribute_key][i] = fields[attr_to_col_ix[attribute_key]] order = np.argsort(indices) ts.positions = ts.positions[order] @@ -904,9 +874,7 @@ def _read_next_timestep(self): if self.lammps_coordinate_convention.startswith("scaled"): # if coordinates are given in scaled format, undo that - ts.positions = distances.transform_StoR( - ts.positions, ts.dimensions - ) + ts.positions = distances.transform_StoR(ts.positions, ts.dimensions) # Transform to origin after transformation of scaled variables ts.positions -= np.array([xlo, ylo, zlo])[None, :] diff --git a/package/MDAnalysis/coordinates/MMTF.py b/package/MDAnalysis/coordinates/MMTF.py index 4e28eed308..94b09fbba1 100644 --- a/package/MDAnalysis/coordinates/MMTF.py +++ b/package/MDAnalysis/coordinates/MMTF.py @@ -76,9 +76,7 @@ def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): ) warnings.warn(wmsg, DeprecationWarning) - super(MMTFReader, self).__init__( - filename, convert_units, n_atoms, **kwargs - ) + super(MMTFReader, self).__init__(filename, convert_units, n_atoms, **kwargs) @staticmethod def _format_hint(thing): diff --git a/package/MDAnalysis/coordinates/MOL2.py b/package/MDAnalysis/coordinates/MOL2.py index 104283e897..f17c23c70b 100644 --- a/package/MDAnalysis/coordinates/MOL2.py +++ b/package/MDAnalysis/coordinates/MOL2.py @@ -145,8 +145,9 @@ class MOL2Reader(base.ReaderBase): .. versionchanged:: 2.2.0 Read MOL2 files with optional columns omitted. """ - format = 'MOL2' - units = {'time': None, 'length': 'Angstrom'} + + format = "MOL2" + units = {"time": None, "length": "Angstrom"} @store_init_arguments def __init__(self, filename, **kwargs): @@ -195,8 +196,10 @@ def parse_block(self, block): atom_lines = sections["atom"] if not len(atom_lines): - raise Exception("The mol2 (starting at line {0}) block has no atoms" - "".format(block["start_line"])) + raise Exception( + "The mol2 (starting at line {0}) block has no atoms" + "".format(block["start_line"]) + ) elif self.n_atoms is None: # First time round, remember the number of atoms self.n_atoms = len(atom_lines) @@ -205,13 +208,14 @@ def parse_block(self, block): "MOL2Reader assumes that the number of atoms remains unchanged" " between frames; the current " "frame has {0}, the next frame has {1} atoms" - "".format(self.n_atoms, len(atom_lines))) + "".format(self.n_atoms, len(atom_lines)) + ) coords = np.zeros((self.n_atoms, 3), dtype=np.float32) for i, a in enumerate(atom_lines): aid, name, x, y, z, atom_type = a.split()[:6] - #x, y, z = float(x), float(y), float(z) + # x, y, z = float(x), float(y), float(z) coords[i, :] = x, y, z return sections, coords @@ -229,13 +233,12 @@ def _read_frame(self, frame): try: block = self.frames[frame] except IndexError: - errmsg = (f"Invalid frame {frame} for trajectory with length " - f"{len(self)}") + errmsg = f"Invalid frame {frame} for trajectory with length " f"{len(self)}" raise IOError(errmsg) from None sections, coords = self.parse_block(block) - for sect in ['molecule', 'substructure']: + for sect in ["molecule", "substructure"]: try: self.ts.data[sect] = sections[sect] except KeyError: @@ -285,9 +288,10 @@ class MOL2Writer(base.WriterBase): Frames now 0-based instead of 1-based """ - format = 'MOL2' + + format = "MOL2" multiframe = True - units = {'time': None, 'length': 'Angstrom'} + units = {"time": None, "length": "Angstrom"} def __init__(self, filename, n_atoms=None, convert_units=True): """Create a new MOL2Writer @@ -304,7 +308,7 @@ def __init__(self, filename, n_atoms=None, convert_units=True): self.frames_written = 0 - self.file = util.anyopen(self.filename, 'w') # open file on init + self.file = util.anyopen(self.filename, "w") # open file on init def close(self): self.file.close() @@ -326,7 +330,7 @@ def encode_block(self, obj): ts = traj.ts try: - molecule = ts.data['molecule'] + molecule = ts.data["molecule"] except KeyError: errmsg = "MOL2Writer cannot currently write non MOL2 data" raise NotImplementedError(errmsg) from None @@ -341,11 +345,12 @@ def encode_block(self, obj): bondgroup = obj.intra_bonds bonds = sorted((b[0], b[1], b.order) for b in bondgroup) bond_lines = ["@BOND"] - bls = ["{0:>5} {1:>5} {2:>5} {3:>2}".format(bid, - mapping[atom1], - mapping[atom2], - order) - for bid, (atom1, atom2, order) in enumerate(bonds, start=1)] + bls = [ + "{0:>5} {1:>5} {2:>5} {3:>2}".format( + bid, mapping[atom1], mapping[atom2], order + ) + for bid, (atom1, atom2, order) in enumerate(bonds, start=1) + ] bond_lines.extend(bls) bond_lines.append("\n") bond_lines = "\n".join(bond_lines) @@ -354,23 +359,27 @@ def encode_block(self, obj): bond_lines = "" atom_lines = ["@ATOM"] - atom_lines.extend("{0:>4} {1:>4} {2:>13.4f} {3:>9.4f} {4:>9.4f}" - " {5:>4} {6} {7} {8:>7.4f}" - "".format(mapping[a], - a.name, - a.position[0], - a.position[1], - a.position[2], - a.type, - a.resid, - a.resname, - a.charge) - for a in obj.atoms) + atom_lines.extend( + "{0:>4} {1:>4} {2:>13.4f} {3:>9.4f} {4:>9.4f}" + " {5:>4} {6} {7} {8:>7.4f}" + "".format( + mapping[a], + a.name, + a.position[0], + a.position[1], + a.position[2], + a.type, + a.resid, + a.resname, + a.charge, + ) + for a in obj.atoms + ) atom_lines.append("\n") atom_lines = "\n".join(atom_lines) try: - substructure = ["@SUBSTRUCTURE\n"] + ts.data['substructure'] + substructure = ["@SUBSTRUCTURE\n"] + ts.data["substructure"] except KeyError: substructure = "" @@ -385,8 +394,7 @@ def encode_block(self, obj): molecule[1] = "{0}\n".format(" ".join(check_sums)) molecule.insert(0, "@MOLECULE\n") - return_val = ("".join(molecule) + atom_lines + - bond_lines + "".join(substructure)) + return_val = "".join(molecule) + atom_lines + bond_lines + "".join(substructure) molecule[0] = molecule_0_store molecule[1] = molecule_1_store diff --git a/package/MDAnalysis/coordinates/NAMDBIN.py b/package/MDAnalysis/coordinates/NAMDBIN.py index 834ea346ae..6e24ba39b6 100644 --- a/package/MDAnalysis/coordinates/NAMDBIN.py +++ b/package/MDAnalysis/coordinates/NAMDBIN.py @@ -66,9 +66,7 @@ def _read_first_frame(self): coord_double = np.fromfile( namdbin, dtype=np.float64, count=self.n_atoms * 3 ) - self.ts._pos[:] = np.array(coord_double, float).reshape( - self.n_atoms, 3 - ) + self.ts._pos[:] = np.array(coord_double, float).reshape(self.n_atoms, 3) @staticmethod def parse_n_atoms(filename, **kwargs): diff --git a/package/MDAnalysis/coordinates/PDB.py b/package/MDAnalysis/coordinates/PDB.py index 5962633976..4e90016477 100644 --- a/package/MDAnalysis/coordinates/PDB.py +++ b/package/MDAnalysis/coordinates/PDB.py @@ -161,7 +161,7 @@ logger = logging.getLogger("MDAnalysis.coordinates.PBD") # Pairs of residue name / atom name in use to deduce PDB formatted atom names -Pair = collections.namedtuple('Atom', 'resname name') +Pair = collections.namedtuple("Atom", "resname name") class PDBReader(base.ReaderBase): @@ -176,7 +176,7 @@ class PDBReader(base.ReaderBase): (:attr:`compound`), *REMARK* (:attr:`remarks`) - all other lines are ignored - + Reads multi-`MODEL`_ PDB files as trajectories. The `Timestep.data` dictionary holds the occupancy and tempfactor (bfactor) values for each atom for a given frame. These attributes are commonly appropriated to store other time varying properties @@ -264,8 +264,9 @@ class PDBReader(base.ReaderBase): Tempfactors (aka bfactors) are now read into the ts.data dictionary each frame. Occupancies are also read into this dictionary. """ - format = ['PDB', 'ENT'] - units = {'time': None, 'length': 'Angstrom'} + + format = ["PDB", "ENT"] + units = {"time": None, "length": "Angstrom"} @store_init_arguments def __init__(self, filename, **kwargs): @@ -280,7 +281,7 @@ def __init__(self, filename, **kwargs): super(PDBReader, self).__init__(filename, **kwargs) try: - self.n_atoms = kwargs['n_atoms'] + self.n_atoms = kwargs["n_atoms"] except KeyError: # hackish, but should work and keeps things DRY # regular MDA usage via Universe doesn't follow this route @@ -309,10 +310,12 @@ def __init__(self, filename, **kwargs): crysts = [] # hack for streamIO - if isinstance(filename, util.NamedStream) and isinstance(filename.stream, StringIO): + if isinstance(filename, util.NamedStream) and isinstance( + filename.stream, StringIO + ): filename.stream = BytesIO(filename.stream.getvalue().encode()) - pdbfile = self._pdbfile = util.anyopen(filename, 'rb') + pdbfile = self._pdbfile = util.anyopen(filename, "rb") line = "magical" while line: @@ -320,21 +323,21 @@ def __init__(self, filename, **kwargs): # (rather than end of current chunk) line = pdbfile.readline() - if line[:5] == b'MODEL': + if line[:5] == b"MODEL": models.append(pdbfile.tell()) - elif line[:5] == b'CRYST': + elif line[:5] == b"CRYST": # remove size of line to get **start** of CRYST line crysts.append(pdbfile.tell() - len(line)) - elif line[:6] == b'HEADER': + elif line[:6] == b"HEADER": # classification = line[10:50] # date = line[50:59] # idCode = line[62:66] header = line[10:66].strip().decode() - elif line[:5] == b'TITLE': + elif line[:5] == b"TITLE": title.append(line[8:80].strip().decode()) - elif line[:6] == b'COMPND': + elif line[:6] == b"COMPND": compound.append(line[7:80].strip().decode()) - elif line[:6] == b'REMARK': + elif line[:6] == b"REMARK": remarks.append(line[6:].strip().decode()) end = pdbfile.tell() # where the file ends @@ -373,14 +376,14 @@ def Writer(self, filename, **kwargs): :class:`PDBWriter` """ - kwargs.setdefault('multiframe', self.n_frames > 1) + kwargs.setdefault("multiframe", self.n_frames > 1) return PDBWriter(filename, **kwargs) def _reopen(self): # Pretend the current TS is -1 (in 0 based) so "next" is the # 0th frame self.close() - self._pdbfile = util.anyopen(self.filename, 'rb') + self._pdbfile = util.anyopen(self.filename, "rb") self.ts.frame = -1 def _read_next_timestep(self, ts=None): @@ -432,7 +435,7 @@ def _read_frame(self, frame): tmp_buf = [] for line in chunk.splitlines(): - if line[:6] in ('ATOM ', 'HETATM'): + if line[:6] in ("ATOM ", "HETATM"): # we only care about coordinates tmp_buf.append([line[30:38], line[38:46], line[46:54]]) try: @@ -448,35 +451,50 @@ def _read_frame(self, frame): else: saw_tempfactor = True pos += 1 - elif line[:6] == 'CRYST1': + elif line[:6] == "CRYST1": # does an implicit str -> float conversion try: - cell_dims = np.array([line[6:15], line[15:24], - line[24:33], line[33:40], - line[40:47], line[47:54]], - dtype=np.float32) + cell_dims = np.array( + [ + line[6:15], + line[15:24], + line[24:33], + line[33:40], + line[40:47], + line[47:54], + ], + dtype=np.float32, + ) except ValueError: - warnings.warn("Failed to read CRYST1 record, " - "possibly invalid PDB file, got:\n{}" - "".format(line)) + warnings.warn( + "Failed to read CRYST1 record, " + "possibly invalid PDB file, got:\n{}" + "".format(line) + ) self.ts.dimensions = None else: - if np.allclose(cell_dims, np.array([1.0, 1.0, 1.0, 90.0, 90.0, 90.0])): - warnings.warn("1 A^3 CRYST1 record," - " this is usually a placeholder." - " Unit cell dimensions will be set to None.") + if np.allclose( + cell_dims, np.array([1.0, 1.0, 1.0, 90.0, 90.0, 90.0]) + ): + warnings.warn( + "1 A^3 CRYST1 record," + " this is usually a placeholder." + " Unit cell dimensions will be set to None." + ) self.ts.dimensions = None else: self.ts.dimensions = cell_dims # check if atom number changed if pos != self.n_atoms: - raise ValueError("Inconsistency in file '{}': The number of atoms " - "({}) in trajectory frame {} differs from the " - "number of atoms ({}) in the corresponding " - "topology.\nTrajectories with varying numbers of " - "atoms are currently not supported." - "".format(self.filename, pos, frame, self.n_atoms)) + raise ValueError( + "Inconsistency in file '{}': The number of atoms " + "({}) in trajectory frame {} differs from the " + "number of atoms ({}) in the corresponding " + "topology.\nTrajectories with varying numbers of " + "atoms are currently not supported." + "".format(self.filename, pos, frame, self.n_atoms) + ) # doing the conversion from list to array at the end is faster self.ts.positions = tmp_buf @@ -487,9 +505,9 @@ def _read_frame(self, frame): if not self.ts.dimensions is None: self.convert_pos_from_native(self.ts.dimensions[:3]) self.ts.frame = frame - self.ts.data['occupancy'] = occupancy + self.ts.data["occupancy"] = occupancy if saw_tempfactor: - self.ts.data['tempfactor'] = tempfactor + self.ts.data["tempfactor"] = tempfactor return self.ts @@ -586,32 +604,37 @@ class PDBWriter(base.WriterBase): Do not write unusable conect records when ag index is larger than 100000. """ + fmt = { - 'ATOM': ( + "ATOM": ( "ATOM {serial:5d} {name:<4s}{altLoc:<1s}{resName:<4s}" "{chainID:1s}{resSeq:4d}{iCode:1s}" " {pos[0]:8.3f}{pos[1]:8.3f}{pos[2]:8.3f}{occupancy:6.2f}" - "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n"), - 'HETATM': ( + "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n" + ), + "HETATM": ( "HETATM{serial:5d} {name:<4s}{altLoc:<1s}{resName:<4s}" "{chainID:1s}{resSeq:4d}{iCode:1s}" " {pos[0]:8.3f}{pos[1]:8.3f}{pos[2]:8.3f}{occupancy:6.2f}" - "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n"), - 'REMARK': "REMARK {0}\n", - 'COMPND': "COMPND {0}\n", - 'HEADER': "HEADER {0}\n", - 'TITLE': "TITLE {0}\n", - 'MODEL': "MODEL {0:>4d}\n", - 'NUMMDL': "NUMMDL {0:5d}\n", - 'ENDMDL': "ENDMDL\n", - 'END': "END\n", - 'CRYST1': ("CRYST1{box[0]:9.3f}{box[1]:9.3f}{box[2]:9.3f}" - "{ang[0]:7.2f}{ang[1]:7.2f}{ang[2]:7.2f} " - "{spacegroup:<11s}{zvalue:4d}\n"), - 'CONECT': "CONECT{0}\n" + "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n" + ), + "REMARK": "REMARK {0}\n", + "COMPND": "COMPND {0}\n", + "HEADER": "HEADER {0}\n", + "TITLE": "TITLE {0}\n", + "MODEL": "MODEL {0:>4d}\n", + "NUMMDL": "NUMMDL {0:5d}\n", + "ENDMDL": "ENDMDL\n", + "END": "END\n", + "CRYST1": ( + "CRYST1{box[0]:9.3f}{box[1]:9.3f}{box[2]:9.3f}" + "{ang[0]:7.2f}{ang[1]:7.2f}{ang[2]:7.2f} " + "{spacegroup:<11s}{zvalue:4d}\n" + ), + "CONECT": "CONECT{0}\n", } - format = ['PDB', 'ENT'] - units = {'time': None, 'length': 'Angstrom'} + format = ["PDB", "ENT"] + units = {"time": None, "length": "Angstrom"} pdb_coor_limits = {"min": -999.9995, "max": 9999.9995} #: wrap comments into REMARK records that are not longer than # :attr:`remark_max_length` characters. @@ -619,36 +642,97 @@ class PDBWriter(base.WriterBase): multiframe = False # These attributes are used to deduce how to format the atom name. - ions = ('FE', 'AS', 'ZN', 'MG', 'MN', 'CO', 'BR', - 'CU', 'TA', 'MO', 'AL', 'BE', 'SE', 'PT', - 'EU', 'NI', 'IR', 'RH', 'AU', 'GD', 'RU') + ions = ( + "FE", + "AS", + "ZN", + "MG", + "MN", + "CO", + "BR", + "CU", + "TA", + "MO", + "AL", + "BE", + "SE", + "PT", + "EU", + "NI", + "IR", + "RH", + "AU", + "GD", + "RU", + ) # Mercurial can be confused for hydrogen gamma. Yet, mercurial is # rather rare in the PDB. Here are all the residues that contain # mercurial. - special_hg = ('CMH', 'EMC', 'MBO', 'MMC', 'HGB', 'BE7', 'PMB') + special_hg = ("CMH", "EMC", "MBO", "MMC", "HGB", "BE7", "PMB") # Chloride can be confused for a carbon. Here are the residues that # contain chloride. - special_cl = ('0QE', 'CPT', 'DCE', 'EAA', 'IMN', 'OCZ', 'OMY', 'OMZ', - 'UN9', '1N1', '2T8', '393', '3MY', 'BMU', 'CLM', 'CP6', - 'DB8', 'DIF', 'EFZ', 'LUR', 'RDC', 'UCL', 'XMM', 'HLT', - 'IRE', 'LCP', 'PCI', 'VGH') + special_cl = ( + "0QE", + "CPT", + "DCE", + "EAA", + "IMN", + "OCZ", + "OMY", + "OMZ", + "UN9", + "1N1", + "2T8", + "393", + "3MY", + "BMU", + "CLM", + "CP6", + "DB8", + "DIF", + "EFZ", + "LUR", + "RDC", + "UCL", + "XMM", + "HLT", + "IRE", + "LCP", + "PCI", + "VGH", + ) # In these pairs, the atom name is aligned on the first column # (column 13). - include_pairs = (Pair('OEC', 'CA1'), - Pair('PLL', 'PD'), - Pair('OEX', 'CA1')) + include_pairs = (Pair("OEC", "CA1"), Pair("PLL", "PD"), Pair("OEX", "CA1")) # In these pairs, the atom name is aligned on the second column # (column 14), but other rules would align them on the first column. - exclude_pairs = (Pair('C14', 'C14'), Pair('C15', 'C15'), - Pair('F9F', 'F9F'), Pair('OAN', 'OAN'), - Pair('BLM', 'NI'), Pair('BZG', 'CO'), - Pair('BZG', 'NI'), Pair('VNL', 'CO1'), - Pair('VNL', 'CO2'), Pair('PF5', 'FE1'), - Pair('PF5', 'FE2'), Pair('UNL', 'UNL')) - - def __init__(self, filename, bonds="conect", n_atoms=None, start=0, step=1, - remarks="Created by PDBWriter", - convert_units=True, multiframe=None, reindex=True): + exclude_pairs = ( + Pair("C14", "C14"), + Pair("C15", "C15"), + Pair("F9F", "F9F"), + Pair("OAN", "OAN"), + Pair("BLM", "NI"), + Pair("BZG", "CO"), + Pair("BZG", "NI"), + Pair("VNL", "CO1"), + Pair("VNL", "CO2"), + Pair("PF5", "FE1"), + Pair("PF5", "FE2"), + Pair("UNL", "UNL"), + ) + + def __init__( + self, + filename, + bonds="conect", + n_atoms=None, + start=0, + step=1, + remarks="Created by PDBWriter", + convert_units=True, + multiframe=None, + reindex=True, + ): """Create a new PDBWriter Parameters @@ -701,7 +785,7 @@ def __init__(self, filename, bonds="conect", n_atoms=None, start=0, step=1, self.step = step self.remarks = remarks - self.pdbfile = util.anyopen(self.filename, 'wt') # open file on init + self.pdbfile = util.anyopen(self.filename, "wt") # open file on init self.has_END = False self.first_frame_done = False @@ -713,23 +797,28 @@ def close(self): .. versionchanged:: 2.0.0 CONECT_ record written just before END_ record """ - if hasattr(self, 'pdbfile') and self.pdbfile is not None: + if hasattr(self, "pdbfile") and self.pdbfile is not None: if not self.has_END: self._write_pdb_bonds() self.END() else: - logger.warning("END record has already been written" - " before the final closing of the file") + logger.warning( + "END record has already been written" + " before the final closing of the file" + ) self.pdbfile.close() self.pdbfile = None def _write_pdb_title(self): if self._multiframe: - self.TITLE("MDANALYSIS FRAMES FROM {0:d}, STEP {1:d}: {2!s}" - "".format(self.start, self.step, self.remarks)) + self.TITLE( + "MDANALYSIS FRAMES FROM {0:d}, STEP {1:d}: {2!s}" + "".format(self.start, self.step, self.remarks) + ) else: - self.TITLE("MDANALYSIS FRAME {0:d}: {1!s}" - "".format(self.start, self.remarks)) + self.TITLE( + "MDANALYSIS FRAME {0:d}: {1!s}" "".format(self.start, self.remarks) + ) def _write_pdb_header(self): """ @@ -786,8 +875,10 @@ def _write_pdb_header(self): self.REMARK("285 CRYST1 RECORD IS INCLUDED, BUT THE VALUES ON") self.REMARK("285 THIS RECORD ARE MEANINGLESS.") - warnings.warn("Unit cell dimensions not found. " - "CRYST1 record set to unitary values.") + warnings.warn( + "Unit cell dimensions not found. " + "CRYST1 record set to unitary values." + ) else: self.CRYST1(self.convert_dimensions_to_unitcell(u.trajectory.ts)) @@ -820,9 +911,11 @@ def _check_pdb_coordinates(self): # such) or add a REMARK (which allows the user to look at the # previously written frames) if self.frames_written > 1: - self.REMARK("Incomplete multi-frame trajectory.", - "Coordinates for the current frame cannot be " - "represented in the PDB format.") + self.REMARK( + "Incomplete multi-frame trajectory.", + "Coordinates for the current frame cannot be " + "represented in the PDB format.", + ) self.close() else: self.close() @@ -839,31 +932,33 @@ def _check_pdb_coordinates(self): else: raise - raise ValueError("PDB files must have coordinate values between " - "{0:.3f} and {1:.3f} Angstroem: file writing was " - "aborted.".format(self.pdb_coor_limits["min"], - self.pdb_coor_limits["max"])) + raise ValueError( + "PDB files must have coordinate values between " + "{0:.3f} and {1:.3f} Angstroem: file writing was " + "aborted.".format(self.pdb_coor_limits["min"], self.pdb_coor_limits["max"]) + ) def _write_pdb_bonds(self): """Writes out all the bond records""" if self.bonds is None: return - if (not hasattr(self, "obj") or - not self.obj or - not hasattr(self.obj.universe, 'bonds')): + if ( + not hasattr(self, "obj") + or not self.obj + or not hasattr(self.obj.universe, "bonds") + ): return bondset = set(itertools.chain(*(a.bonds for a in self.obj.atoms))) if self._reindex: - index_attribute = 'index' + index_attribute = "index" mapping = { - index: i - for i, index in enumerate(self.obj.atoms.indices, start=1) + index: i for i, index in enumerate(self.obj.atoms.indices, start=1) } atoms = np.sort(self.obj.atoms.indices) else: - index_attribute = 'id' + index_attribute = "id" mapping = {id_: id_ for id_ in self.obj.atoms.ids} atoms = np.sort(self.obj.atoms.ids) if self.bonds == "conect": @@ -873,7 +968,8 @@ def _write_pdb_bonds(self): getattr(bond[0], index_attribute), getattr(bond[1], index_attribute), ) - for bond in bondset if not bond.is_guessed + for bond in bondset + if not bond.is_guessed ) elif self.bonds == "all": bonds = ( @@ -891,14 +987,19 @@ def _write_pdb_bonds(self): if not (a1 in mapping and a2 in mapping): continue if mapping[a1] >= 100000 or mapping[a2] >= 100000: - warnings.warn("Atom with index >=100000 cannot write " - "bonds to PDB CONECT records.") + warnings.warn( + "Atom with index >=100000 cannot write " + "bonds to PDB CONECT records." + ) return con[a2].append(a1) con[a1].append(a2) - conect = ([mapping[a]] + sorted([mapping[at] for at in con[a]]) - for a in atoms if a in con) + conect = ( + [mapping[a]] + sorted([mapping[at] for at in con[a]]) + for a in atoms + if a in con + ) for c in conect: self.CONECT(c) @@ -921,9 +1022,11 @@ def _update_frame(self, obj): current frame. """ if isinstance(obj, Timestep): - raise TypeError("PDBWriter cannot write Timestep objects " - "directly, since they lack topology information (" - "atom names and types) required in PDB files") + raise TypeError( + "PDBWriter cannot write Timestep objects " + "directly, since they lack topology information (" + "atom names and types) required in PDB files" + ) if len(obj.atoms) == 0: raise IndexError("Cannot write empty AtomGroup") @@ -1010,7 +1113,7 @@ def write_all_timesteps(self, obj): traj[start] def _write_next_frame(self, ts=None, **kwargs): - '''write a new timestep to the PDB file + """write a new timestep to the PDB file :Keywords: *ts* @@ -1029,13 +1132,12 @@ def _write_next_frame(self, ts=None, **kwargs): .. versionchanged:: 1.0.0 Renamed from `write_next_timestep` to `_write_next_frame`. - ''' + """ if ts is None: try: ts = self.ts except AttributeError: - errmsg = ("PBDWriter: no coordinate data to write to " - "trajectory file") + errmsg = "PBDWriter: no coordinate data to write to " "trajectory file" raise NoDataError(errmsg) from None self._check_pdb_coordinates() self._write_timestep(ts, **kwargs) @@ -1051,21 +1153,22 @@ def _deduce_PDB_atom_name(self, atomname, resname): for more details. """ - if atomname == '': - return '' + if atomname == "": + return "" if len(atomname) >= 4: return atomname[:4] elif len(atomname) == 1: - return ' {} '.format(atomname) - elif ((resname == atomname - or atomname[:2] in self.ions - or atomname == 'UNK' - or (resname in self.special_hg and atomname[:2] == 'HG') - or (resname in self.special_cl and atomname[:2] == 'CL') - or Pair(resname, atomname) in self.include_pairs) - and Pair(resname, atomname) not in self.exclude_pairs): - return '{:<4}'.format(atomname) - return ' {:<3}'.format(atomname) + return " {} ".format(atomname) + elif ( + resname == atomname + or atomname[:2] in self.ions + or atomname == "UNK" + or (resname in self.special_hg and atomname[:2] == "HG") + or (resname in self.special_cl and atomname[:2] == "CL") + or Pair(resname, atomname) in self.include_pairs + ) and Pair(resname, atomname) not in self.exclude_pairs: + return "{:<4}".format(atomname) + return " {:<3}".format(atomname) @staticmethod def _format_PDB_charges(charges: np.ndarray) -> np.ndarray: @@ -1094,7 +1197,7 @@ def _format_PDB_charges(charges: np.ndarray) -> np.ndarray: raise ValueError("formal charges array should be of `int` type") outcharges = charges.astype(object) - outcharges[outcharges == 0] = '' # empty strings for no charge case + outcharges[outcharges == 0] = "" # empty strings for no charge case # using np.where is more efficient than looping in sparse cases for i in np.where(charges < 0)[0]: if charges[i] < -9: @@ -1163,22 +1266,25 @@ def get_attr(attrname, default): return getattr(atoms, attrname) except AttributeError: if self.frames_written == 0: - warnings.warn("Found no information for attr: '{}'" - " Using default value of '{}'" - "".format(attrname, default)) + warnings.warn( + "Found no information for attr: '{}'" + " Using default value of '{}'" + "".format(attrname, default) + ) return np.array([default] * len(atoms)) - altlocs = get_attr('altLocs', ' ') - resnames = get_attr('resnames', 'UNK') - icodes = get_attr('icodes', ' ') - segids = get_attr('segids', ' ') - chainids = get_attr('chainIDs', '') - resids = get_attr('resids', 1) - occupancies = get_attr('occupancies', 1.0) - tempfactors = get_attr('tempfactors', 0.0) - atomnames = get_attr('names', 'X') - elements = get_attr('elements', ' ') - record_types = get_attr('record_types', 'ATOM') - formal_charges = self._format_PDB_charges(get_attr('formalcharges', 0)) + + altlocs = get_attr("altLocs", " ") + resnames = get_attr("resnames", "UNK") + icodes = get_attr("icodes", " ") + segids = get_attr("segids", " ") + chainids = get_attr("chainIDs", "") + resids = get_attr("resids", 1) + occupancies = get_attr("occupancies", 1.0) + tempfactors = get_attr("tempfactors", 0.0) + atomnames = get_attr("names", "X") + elements = get_attr("elements", " ") + record_types = get_attr("record_types", "ATOM") + formal_charges = self._format_PDB_charges(get_attr("formalcharges", 0)) def validate_chainids(chainids, default): """Validate each atom's chainID @@ -1190,7 +1296,7 @@ def validate_chainids(chainids, default): invalid_char_ids = False missing_ids = False - for (i, chainid) in enumerate(chainids): + for i, chainid in enumerate(chainids): if chainid == "": missing_ids = True chainids[i] = default @@ -1202,17 +1308,23 @@ def validate_chainids(chainids, default): chainids[i] = default if invalid_length_ids: - warnings.warn("Found chainIDs with invalid length." - " Corresponding atoms will use value of '{}'" - "".format(default)) + warnings.warn( + "Found chainIDs with invalid length." + " Corresponding atoms will use value of '{}'" + "".format(default) + ) if invalid_char_ids: - warnings.warn("Found chainIDs using unnaccepted character." - " Corresponding atoms will use value of '{}'" - "".format(default)) + warnings.warn( + "Found chainIDs using unnaccepted character." + " Corresponding atoms will use value of '{}'" + "".format(default) + ) if missing_ids: - warnings.warn("Found missing chainIDs." - " Corresponding atoms will use value of '{}'" - "".format(default)) + warnings.warn( + "Found missing chainIDs." + " Corresponding atoms will use value of '{}'" + "".format(default) + ) return chainids chainids = validate_chainids(chainids, "X") @@ -1225,33 +1337,37 @@ def validate_chainids(chainids, default): except AttributeError: raise NoDataError( 'The "id" topology attribute is not set. ' - 'Either set the attribute or use reindex=True.' + "Either set the attribute or use reindex=True." ) else: atom_ids = np.arange(len(atoms)) + 1 for i in range(len(atoms)): vals = {} - vals['serial'] = util.ltruncate_int(atom_ids[i], 5) # check for overflow here? - vals['name'] = self._deduce_PDB_atom_name(atomnames[i], resnames[i]) - vals['altLoc'] = altlocs[i][:1] - vals['resName'] = resnames[i][:4] - vals['resSeq'] = util.ltruncate_int(resids[i], 4) - vals['iCode'] = icodes[i][:1] - vals['pos'] = pos[i] # don't take off atom so conversion works - vals['occupancy'] = occupancies[i] - vals['tempFactor'] = tempfactors[i] - vals['segID'] = segids[i][:4] - vals['chainID'] = chainids[i] - vals['element'] = elements[i][:2].upper() - vals['charge'] = formal_charges[i] + vals["serial"] = util.ltruncate_int( + atom_ids[i], 5 + ) # check for overflow here? + vals["name"] = self._deduce_PDB_atom_name(atomnames[i], resnames[i]) + vals["altLoc"] = altlocs[i][:1] + vals["resName"] = resnames[i][:4] + vals["resSeq"] = util.ltruncate_int(resids[i], 4) + vals["iCode"] = icodes[i][:1] + vals["pos"] = pos[i] # don't take off atom so conversion works + vals["occupancy"] = occupancies[i] + vals["tempFactor"] = tempfactors[i] + vals["segID"] = segids[i][:4] + vals["chainID"] = chainids[i] + vals["element"] = elements[i][:2].upper() + vals["charge"] = formal_charges[i] # record_type attribute, if exists, can be ATOM or HETATM try: self.pdbfile.write(self.fmt[record_types[i]].format(**vals)) except KeyError: - errmsg = (f"Found {record_types[i]} for the record type, but " - f"only allowed types are ATOM or HETATM") + errmsg = ( + f"Found {record_types[i]} for the record type, but " + f"only allowed types are ATOM or HETATM" + ) raise ValueError(errmsg) from None if multiframe: @@ -1265,17 +1381,15 @@ def HEADER(self, trajectory): Strip `trajectory.header` since it can be modified by the user and should be sanitized (Issue #2324) """ - if not hasattr(trajectory, 'header'): + if not hasattr(trajectory, "header"): return header = trajectory.header.strip() - self.pdbfile.write(self.fmt['HEADER'].format(header)) + self.pdbfile.write(self.fmt["HEADER"].format(header)) def TITLE(self, *title): - """Write TITLE_ record. - - """ + """Write TITLE_ record.""" line = " ".join(title) # TODO: should do continuation automatically - self.pdbfile.write(self.fmt['TITLE'].format(line)) + self.pdbfile.write(self.fmt["TITLE"].format(line)) def REMARK(self, *remarks): """Write generic REMARKS_ record (without number). @@ -1285,23 +1399,25 @@ def REMARK(self, *remarks): """ for remark in remarks: - self.pdbfile.write(self.fmt['REMARK'].format(remark)) + self.pdbfile.write(self.fmt["REMARK"].format(remark)) def COMPND(self, trajectory): - if not hasattr(trajectory, 'compound'): + if not hasattr(trajectory, "compound"): return compound = trajectory.compound for c in compound: - self.pdbfile.write(self.fmt['COMPND'].format(c)) - - def CRYST1(self, dimensions, spacegroup='P 1', zvalue=1): - """Write CRYST1_ record. - """ - self.pdbfile.write(self.fmt['CRYST1'].format( - box=dimensions[:3], - ang=dimensions[3:], - spacegroup=spacegroup, - zvalue=zvalue)) + self.pdbfile.write(self.fmt["COMPND"].format(c)) + + def CRYST1(self, dimensions, spacegroup="P 1", zvalue=1): + """Write CRYST1_ record.""" + self.pdbfile.write( + self.fmt["CRYST1"].format( + box=dimensions[:3], + ang=dimensions[3:], + spacegroup=spacegroup, + zvalue=zvalue, + ) + ) def MODEL(self, modelnumber): """Write the MODEL_ record. @@ -1316,7 +1432,7 @@ def MODEL(self, modelnumber): Maximum model number is enforced. """ - self.pdbfile.write(self.fmt['MODEL'].format(int(str(modelnumber)[-4:]))) + self.pdbfile.write(self.fmt["MODEL"].format(int(str(modelnumber)[-4:]))) def END(self): """Write END_ record. @@ -1329,22 +1445,18 @@ def END(self): """ if not self.has_END: # only write a single END record - self.pdbfile.write(self.fmt['END']) + self.pdbfile.write(self.fmt["END"]) self.has_END = True def ENDMDL(self): - """Write the ENDMDL_ record. - - """ - self.pdbfile.write(self.fmt['ENDMDL']) + """Write the ENDMDL_ record.""" + self.pdbfile.write(self.fmt["ENDMDL"]) def CONECT(self, conect): - """Write CONECT_ record. - - """ + """Write CONECT_ record.""" conect = ["{0:5d}".format(entry) for entry in conect] conect = "".join(conect) - self.pdbfile.write(self.fmt['CONECT'].format(conect)) + self.pdbfile.write(self.fmt["CONECT"].format(conect)) class ExtendedPDBReader(PDBReader): @@ -1365,6 +1477,7 @@ class ExtendedPDBReader(PDBReader): .. versionadded:: 0.8 """ + format = "XPDB" @@ -1394,6 +1507,7 @@ class MultiPDBWriter(PDBWriter): .. versionadded:: 0.7.6 """ - format = ['PDB', 'ENT'] + + format = ["PDB", "ENT"] multiframe = True # For Writer registration singleframe = False diff --git a/package/MDAnalysis/coordinates/PDBQT.py b/package/MDAnalysis/coordinates/PDBQT.py index 5388b1ad9b..e1e0acc578 100644 --- a/package/MDAnalysis/coordinates/PDBQT.py +++ b/package/MDAnalysis/coordinates/PDBQT.py @@ -157,13 +157,9 @@ def _read_first_frame(self): break if line.startswith("CRYST1"): # lengths - x, y, z = np.float32( - (line[6:15], line[15:24], line[24:33]) - ) + x, y, z = np.float32((line[6:15], line[15:24], line[24:33])) # angles - A, B, G = np.float32( - (line[33:40], line[40:47], line[47:54]) - ) + A, B, G = np.float32((line[33:40], line[40:47], line[47:54])) unitcell[:] = x, y, z, A, B, G if line.startswith(("ATOM", "HETATM")): # convert all entries at the end once for optimal speed @@ -268,9 +264,7 @@ def write(self, selection, frame=None): frame = 0 # should catch cases when we are analyzing a single PDB (?) atoms = selection.atoms # make sure to use atoms (Issue 46) - coor = ( - atoms.positions - ) # can write from selection == Universe (Issue 49) + coor = atoms.positions # can write from selection == Universe (Issue 49) # Check attributes attrs = {} @@ -319,9 +313,7 @@ def write(self, selection, frame=None): raise ValueError( "PDB files must have coordinate values between {0:.3f}" " and {1:.3f} Angstroem: No file was written." - "".format( - self.pdb_coor_limits["min"], self.pdb_coor_limits["max"] - ) + "".format(self.pdb_coor_limits["min"], self.pdb_coor_limits["max"]) ) # Write title record diff --git a/package/MDAnalysis/coordinates/PQR.py b/package/MDAnalysis/coordinates/PQR.py index a2f5a119f7..a3381acc67 100644 --- a/package/MDAnalysis/coordinates/PQR.py +++ b/package/MDAnalysis/coordinates/PQR.py @@ -219,9 +219,7 @@ def __init__(self, filename, convert_units=True, **kwargs): top of the PQR file """ self.filename = util.filename(filename, ext="pqr", keep=True) - self.convert_units = ( - convert_units # convert length and time to base units - ) + self.convert_units = convert_units # convert length and time to base units self.remarks = kwargs.pop("remarks", "PQR file written by MDAnalysis") def write(self, selection, frame=None): @@ -256,9 +254,7 @@ def write(self, selection, frame=None): frame = 0 # should catch cases when we are analyzing a single frame(?) atoms = selection.atoms # make sure to use atoms (Issue 46) - coordinates = ( - atoms.positions - ) # can write from selection == Universe (Issue 49) + coordinates = atoms.positions # can write from selection == Universe (Issue 49) if self.convert_units: self.convert_pos_to_native( coordinates @@ -322,9 +318,7 @@ def write(self, selection, frame=None): pqrfile.write(self.fmt_remark.format(rem, 1)) pqrfile.write( self.fmt_remark.format( - "Input: frame {0} of {1}".format( - frame, u.trajectory.filename - ), + "Input: frame {0} of {1}".format(frame, u.trajectory.filename), 5, ) ) diff --git a/package/MDAnalysis/coordinates/TNG.py b/package/MDAnalysis/coordinates/TNG.py index 44c6890dcf..a5d868360f 100644 --- a/package/MDAnalysis/coordinates/TNG.py +++ b/package/MDAnalysis/coordinates/TNG.py @@ -148,9 +148,7 @@ class TNGReader(base.ReaderBase): _forces_blockname, ] - @due.dcite( - Doi("10.1002/jcc.23495"), description="The TNG paper", path=__name__ - ) + @due.dcite(Doi("10.1002/jcc.23495"), description="The TNG paper", path=__name__) @store_init_arguments def __init__(self, filename: str, convert_units: bool = True, **kwargs): """Initialize a TNG trajectory @@ -164,9 +162,7 @@ def __init__(self, filename: str, convert_units: bool = True, **kwargs): """ if not HAS_PYTNG: - raise ImportError( - "TNGReader: To read TNG files please install pytng" - ) + raise ImportError("TNGReader: To read TNG files please install pytng") super(TNGReader, self).__init__(filename, **kwargs) @@ -197,35 +193,27 @@ def __init__(self, filename: str, convert_units: bool = True, **kwargs): self._has_positions = self._positions_blockname in self._block_names if self._has_positions: self._special_block_present[self._positions_blockname] = True - self.ts.positions = ( - self._file_iterator.make_ndarray_for_block_from_name( - self._positions_blockname - ) + self.ts.positions = self._file_iterator.make_ndarray_for_block_from_name( + self._positions_blockname ) self._has_velocities = self._velocities_blockname in self._block_names if self._has_velocities: self._special_block_present[self._velocities_blockname] = True - self.ts.velocities = ( - self._file_iterator.make_ndarray_for_block_from_name( - self._velocities_blockname - ) + self.ts.velocities = self._file_iterator.make_ndarray_for_block_from_name( + self._velocities_blockname ) self._has_forces = self._forces_blockname in self._block_names if self._has_forces: self._special_block_present[self._forces_blockname] = True - self.ts.forces = ( - self._file_iterator.make_ndarray_for_block_from_name( - self._forces_blockname - ) + self.ts.forces = self._file_iterator.make_ndarray_for_block_from_name( + self._forces_blockname ) # check for any additional blocks that will be read into ts.data self._additional_blocks = [ - block - for block in self._block_names - if block not in self._special_blocks + block for block in self._block_names if block not in self._special_blocks ] self._check_strides_and_frames() self._frame = 0 @@ -277,9 +265,7 @@ def _check_strides_and_frames(self): " It will not be read" ) else: - self._additional_blocks_to_read.append( - block - ) # pragma: no cover + self._additional_blocks_to_read.append(block) # pragma: no cover else: self._additional_blocks_to_read.append(block) @@ -303,9 +289,7 @@ def parse_n_atoms(filename: str) -> int: """ if not HAS_PYTNG: - raise ImportError( - "TNGReader: To read TNG files please install pytng" - ) + raise ImportError("TNGReader: To read TNG files please install pytng") with pytng.TNGFileIterator(filename, "r") as tng: n_atoms = tng.n_atoms return n_atoms @@ -487,9 +471,7 @@ def _frame_to_ts( add_block_stride = self._block_strides[block] # check we are on stride for our block if not (add_block_stride % self._global_stride): - block_data = ( - self._file_iterator.make_ndarray_for_block_from_name(block) - ) + block_data = self._file_iterator.make_ndarray_for_block_from_name(block) # additional blocks read into ts.data dictionary ts.data[block] = curr_step.get_blockid( self._block_dictionary[block], block_data diff --git a/package/MDAnalysis/coordinates/TRC.py b/package/MDAnalysis/coordinates/TRC.py index 4c7c4009ec..8e0e755caf 100644 --- a/package/MDAnalysis/coordinates/TRC.py +++ b/package/MDAnalysis/coordinates/TRC.py @@ -229,9 +229,7 @@ def _read_traj_properties(self): # Timestep-block # if "TIMESTEP" == stripped_line: - l_timestep_timevalues.append( - float(f.readline().split()[1]) - ) + l_timestep_timevalues.append(float(f.readline().split()[1])) while stripped_line != "END": stripped_line = f.readline().strip() # @@ -268,9 +266,7 @@ def _read_traj_properties(self): # instead of looping over the file, looking for an END # we can seek to where the end of the block should be. current_pos = f.tell() - len(line) - f.seek( - f.tell() - len(line) + block_size["POSITIONRED"] - ) + f.seek(f.tell() - len(line) + block_size["POSITIONRED"]) # Check if we are at the correct position # If not, set inconsistent_size to true and seek back @@ -283,9 +279,7 @@ def _read_traj_properties(self): f.seek(current_pos) if frame_counter == 0: - errormsg = ( - "No supported blocks were found within the GROMOS trajectory!" - ) + errormsg = "No supported blocks were found within the GROMOS trajectory!" logger.error(errormsg) raise ValueError(errormsg) @@ -294,9 +288,7 @@ def _read_traj_properties(self): traj_properties["l_blockstart_offset"] = l_blockstart_offset if len(l_timestep_timevalues) >= 2: - traj_properties["dt"] = ( - l_timestep_timevalues[1] - l_timestep_timevalues[0] - ) + traj_properties["dt"] = l_timestep_timevalues[1] - l_timestep_timevalues[0] else: traj_properties["dt"] = 0 warnmsg = "The trajectory does not contain TIMESTEP blocks!" @@ -359,9 +351,7 @@ def _read_GROMOS11_trajectory(self): elif ntb_setting in [1, 2]: tmp_a, tmp_b, tmp_c = map(float, f.readline().split()) - tmp_alpha, tmp_beta, tmp_gamma = map( - float, f.readline().split() - ) + tmp_alpha, tmp_beta, tmp_gamma = map(float, f.readline().split()) frameDat["dimensions"] = [ tmp_a, tmp_b, @@ -373,21 +363,13 @@ def _read_GROMOS11_trajectory(self): self.periodic = True # gb_line3 - if ( - sum(abs(float(v)) for v in f.readline().split()) - > 1e-10 - ): - errormsg = ( - "This reader doesnt't support a shifted origin!" - ) + if sum(abs(float(v)) for v in f.readline().split()) > 1e-10: + errormsg = "This reader doesnt't support a shifted origin!" logger.error(errormsg) raise ValueError(errormsg) # gb_line4 - if ( - sum(abs(float(v)) for v in f.readline().split()) - > 1e-10 - ): + if sum(abs(float(v)) for v in f.readline().split()) > 1e-10: errormsg = "This reader doesnt't support yawed, pitched or rolled boxes!" logger.error(errormsg) raise ValueError(errormsg) @@ -399,8 +381,7 @@ def _read_GROMOS11_trajectory(self): break elif any( - non_supp_bn in line - for non_supp_bn in TRCReader.NOT_SUPPORTED_BLOCKS + non_supp_bn in line for non_supp_bn in TRCReader.NOT_SUPPORTED_BLOCKS ): for non_supp_bn in TRCReader.NOT_SUPPORTED_BLOCKS: if non_supp_bn == stripped_line: @@ -415,9 +396,7 @@ def _read_frame(self, i): self._frame = i - 1 # Move position in file just (-2 byte) before the start of the block - self.trcfile.seek( - self.traj_properties["l_blockstart_offset"][i] - 2, 0 - ) + self.trcfile.seek(self.traj_properties["l_blockstart_offset"][i] - 2, 0) return self._read_next_timestep() diff --git a/package/MDAnalysis/coordinates/TRJ.py b/package/MDAnalysis/coordinates/TRJ.py index e9799e4d94..60ba641151 100644 --- a/package/MDAnalysis/coordinates/TRJ.py +++ b/package/MDAnalysis/coordinates/TRJ.py @@ -141,6 +141,7 @@ from . import base from ..lib import util from ..lib.util import store_init_arguments + logger = logging.getLogger("MDAnalysis.coordinates.AMBER") @@ -172,8 +173,9 @@ class TRJReader(base.ReaderBase): Frames now 0-based instead of 1-based. kwarg `delta` renamed to `dt`, for uniformity with other Readers """ - format = ['TRJ', 'MDCRD', 'CRDBOX'] - units = {'time': 'ps', 'length': 'Angstrom'} + + format = ["TRJ", "MDCRD", "CRDBOX"] + units = {"time": "ps", "length": "Angstrom"} _Timestep = Timestep @store_init_arguments @@ -189,14 +191,14 @@ def __init__(self, filename, n_atoms=None, **kwargs): # FORMAT(10F8.3) (X(i), Y(i), Z(i), i=1,NATOM) self.default_line_parser = util.FORTRANReader("10F8.3") - self.lines_per_frame = int(np.ceil(3.0 * self.n_atoms / len( - self.default_line_parser))) + self.lines_per_frame = int( + np.ceil(3.0 * self.n_atoms / len(self.default_line_parser)) + ) # The last line per frame might have fewer than 10 # We determine right away what parser we need for the last # line because it will be the same for all frames. last_per_line = 3 * self.n_atoms % len(self.default_line_parser) - self.last_line_parser = util.FORTRANReader("{0:d}F8.3".format( - last_per_line)) + self.last_line_parser = util.FORTRANReader("{0:d}F8.3".format(last_per_line)) # FORMAT(10F8.3) BOX(1), BOX(2), BOX(3) # is this always on a separate line?? @@ -241,7 +243,7 @@ def _read_next_timestep(self): if self.periodic: line = next(self.trjfile) box = self.box_line_parser.read(line) - ts.dimensions = box + [90., 90., 90.] # assumed + ts.dimensions = box + [90.0, 90.0, 90.0] # assumed # probably slow ... could be optimized by storing the coordinates in # X,Y,Z lists or directly filling the array; the array/reshape is not @@ -289,7 +291,7 @@ def _detect_amber_box(self): nentries = self.default_line_parser.number_of_matches(line) if nentries == 3: self.periodic = True - ts.dimensions = self.box_line_parser.read(line) + [90., 90., 90.] + ts.dimensions = self.box_line_parser.read(line) + [90.0, 90.0, 90.0] else: self.periodic = False self.close() @@ -340,7 +342,8 @@ def open_trajectory(self): # Chimera uses this check raise OSError( "Header of AMBER formatted trajectory has more than 80 chars. " - "This is probably not a AMBER trajectory.") + "This is probably not a AMBER trajectory." + ) # reset ts ts = self.ts ts.frame = -1 @@ -425,13 +428,15 @@ class NCDFReader(base.ReaderBase): """ - format = ['NCDF', 'NC'] + format = ["NCDF", "NC"] multiframe = True version = "1.0" - units = {'time': 'ps', - 'length': 'Angstrom', - 'velocity': 'Angstrom/ps', - 'force': 'kcal/(mol*Angstrom)'} + units = { + "time": "ps", + "length": "Angstrom", + "velocity": "Angstrom/ps", + "force": "kcal/(mol*Angstrom)", + } _Timestep = Timestep @@ -443,55 +448,60 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): super(NCDFReader, self).__init__(filename, **kwargs) # ensure maskandscale is off so we don't end up double scaling - self.trjfile = NCDFPicklable(self.filename, - mmap=self._mmap, - maskandscale=False) + self.trjfile = NCDFPicklable(self.filename, mmap=self._mmap, maskandscale=False) # AMBER NetCDF files should always have a convention try: conventions = self.trjfile.Conventions - if not ('AMBER' in conventions.decode('utf-8').split(',') or - 'AMBER' in conventions.decode('utf-8').split()): - errmsg = ("NCDF trajectory {0} does not conform to AMBER " - "specifications, " - "http://ambermd.org/netcdf/nctraj.xhtml " - "('AMBER' must be one of the token in attribute " - "Conventions)".format(self.filename)) + if not ( + "AMBER" in conventions.decode("utf-8").split(",") + or "AMBER" in conventions.decode("utf-8").split() + ): + errmsg = ( + "NCDF trajectory {0} does not conform to AMBER " + "specifications, " + "http://ambermd.org/netcdf/nctraj.xhtml " + "('AMBER' must be one of the token in attribute " + "Conventions)".format(self.filename) + ) logger.fatal(errmsg) raise TypeError(errmsg) except AttributeError: - errmsg = "NCDF trajectory {0} is missing Conventions".format( - self.filename) + errmsg = "NCDF trajectory {0} is missing Conventions".format(self.filename) logger.fatal(errmsg) raise ValueError(errmsg) from None # AMBER NetCDF files should also have a ConventionVersion try: - ConventionVersion = self.trjfile.ConventionVersion.decode('utf-8') + ConventionVersion = self.trjfile.ConventionVersion.decode("utf-8") if not ConventionVersion == self.version: - wmsg = ("NCDF trajectory format is {0!s} but the reader " - "implements format {1!s}".format( - ConventionVersion, self.version)) + wmsg = ( + "NCDF trajectory format is {0!s} but the reader " + "implements format {1!s}".format(ConventionVersion, self.version) + ) warnings.warn(wmsg) logger.warning(wmsg) except AttributeError: errmsg = "NCDF trajectory {0} is missing ConventionVersion".format( - self.filename) + self.filename + ) raise ValueError(errmsg) from None # The AMBER NetCDF standard enforces 64 bit offsets if not self.trjfile.version_byte == 2: - errmsg = ("NCDF trajectory {0} does not conform to AMBER " - "specifications, as detailed in " - "https://ambermd.org/netcdf/nctraj.xhtml " - "(NetCDF file does not use 64 bit offsets " - "[version_byte = 2])".format(self.filename)) + errmsg = ( + "NCDF trajectory {0} does not conform to AMBER " + "specifications, as detailed in " + "https://ambermd.org/netcdf/nctraj.xhtml " + "(NetCDF file does not use 64 bit offsets " + "[version_byte = 2])".format(self.filename) + ) logger.fatal(errmsg) raise TypeError(errmsg) # The AMBER NetCDF standard enforces 3D coordinates try: - if not self.trjfile.dimensions['spatial'] == 3: + if not self.trjfile.dimensions["spatial"] == 3: errmsg = "Incorrect spatial value for NCDF trajectory file" raise TypeError(errmsg) except KeyError: @@ -500,38 +510,46 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): # AMBER NetCDF specs require program and programVersion. Warn users # if those attributes do not exist - if not (hasattr(self.trjfile, 'program') and - hasattr(self.trjfile, 'programVersion')): - wmsg = ("NCDF trajectory {0} may not fully adhere to AMBER " - "standards as either the `program` or `programVersion` " - "attributes are missing".format(self.filename)) + if not ( + hasattr(self.trjfile, "program") and hasattr(self.trjfile, "programVersion") + ): + wmsg = ( + "NCDF trajectory {0} may not fully adhere to AMBER " + "standards as either the `program` or `programVersion` " + "attributes are missing".format(self.filename) + ) warnings.warn(wmsg) logger.warning(wmsg) try: - self.n_atoms = self.trjfile.dimensions['atom'] + self.n_atoms = self.trjfile.dimensions["atom"] if n_atoms is not None and n_atoms != self.n_atoms: - errmsg = ("Supplied n_atoms ({0}) != natom from ncdf ({1}). " - "Note: n_atoms can be None and then the ncdf value " - "is used!".format(n_atoms, self.n_atoms)) + errmsg = ( + "Supplied n_atoms ({0}) != natom from ncdf ({1}). " + "Note: n_atoms can be None and then the ncdf value " + "is used!".format(n_atoms, self.n_atoms) + ) raise ValueError(errmsg) except KeyError: - errmsg = ("NCDF trajectory {0} does not contain atom " - "information".format(self.filename)) + errmsg = "NCDF trajectory {0} does not contain atom " "information".format( + self.filename + ) raise ValueError(errmsg) from None try: - self.n_frames = self.trjfile.dimensions['frame'] + self.n_frames = self.trjfile.dimensions["frame"] # example trajectory when read with scipy.io.netcdf has # dimensions['frame'] == None (indicating a record dimension that # can grow) whereas if read with netCDF4 I get # len(dimensions['frame']) == 10: in any case, we need to get # the number of frames from somewhere such as the time variable: if self.n_frames is None: - self.n_frames = self.trjfile.variables['coordinates'].shape[0] + self.n_frames = self.trjfile.variables["coordinates"].shape[0] except KeyError: - errmsg = (f"NCDF trajectory {self.filename} does not contain " - f"frame information") + errmsg = ( + f"NCDF trajectory {self.filename} does not contain " + f"frame information" + ) raise ValueError(errmsg) from None try: @@ -545,81 +563,91 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): # checks for not-implemented features (other units would need to be # hacked into MDAnalysis.units) try: - self._verify_units(self.trjfile.variables['time'].units, 'picosecond') + self._verify_units(self.trjfile.variables["time"].units, "picosecond") self.has_time = True except KeyError: self.has_time = False - wmsg = ("NCDF trajectory does not contain `time` information;" - " `time` will be set as an increasing index") + wmsg = ( + "NCDF trajectory does not contain `time` information;" + " `time` will be set as an increasing index" + ) warnings.warn(wmsg) logger.warning(wmsg) - - self._verify_units(self.trjfile.variables['coordinates'].units, - 'angstrom') + self._verify_units(self.trjfile.variables["coordinates"].units, "angstrom") # Check for scale_factor attributes for all data variables and # store this to multiply through later (Issue #2323) - self.scale_factors = {'time': None, - 'cell_lengths': None, - 'cell_angles': None, - 'coordinates': None, - 'velocities': None, - 'forces': None} + self.scale_factors = { + "time": None, + "cell_lengths": None, + "cell_angles": None, + "coordinates": None, + "velocities": None, + "forces": None, + } for variable in self.trjfile.variables: - if hasattr(self.trjfile.variables[variable], 'scale_factor'): + if hasattr(self.trjfile.variables[variable], "scale_factor"): if variable in self.scale_factors: scale_factor = self.trjfile.variables[variable].scale_factor if not isinstance(scale_factor, (float, np.floating)): raise TypeError(f"{scale_factor} is not a float") self.scale_factors[variable] = scale_factor else: - errmsg = ("scale_factors for variable {0} are " - "not implemented".format(variable)) + errmsg = ( + "scale_factors for variable {0} are " + "not implemented".format(variable) + ) raise NotImplementedError(errmsg) - self.has_velocities = 'velocities' in self.trjfile.variables + self.has_velocities = "velocities" in self.trjfile.variables if self.has_velocities: - self._verify_units(self.trjfile.variables['velocities'].units, - 'angstrom/picosecond') + self._verify_units( + self.trjfile.variables["velocities"].units, "angstrom/picosecond" + ) - self.has_forces = 'forces' in self.trjfile.variables + self.has_forces = "forces" in self.trjfile.variables if self.has_forces: - self._verify_units(self.trjfile.variables['forces'].units, - 'kilocalorie/mole/angstrom') + self._verify_units( + self.trjfile.variables["forces"].units, "kilocalorie/mole/angstrom" + ) - self.periodic = 'cell_lengths' in self.trjfile.variables + self.periodic = "cell_lengths" in self.trjfile.variables if self.periodic: - self._verify_units(self.trjfile.variables['cell_lengths'].units, - 'angstrom') + self._verify_units(self.trjfile.variables["cell_lengths"].units, "angstrom") # As of v1.0.0 only `degree` is accepted as a unit - cell_angle_units = self.trjfile.variables['cell_angles'].units - self._verify_units(cell_angle_units, 'degree') + cell_angle_units = self.trjfile.variables["cell_angles"].units + self._verify_units(cell_angle_units, "degree") self._current_frame = 0 - self.ts = self._Timestep(self.n_atoms, - velocities=self.has_velocities, - forces=self.has_forces, - reader=self, # for dt - **self._ts_kwargs) + self.ts = self._Timestep( + self.n_atoms, + velocities=self.has_velocities, + forces=self.has_forces, + reader=self, # for dt + **self._ts_kwargs, + ) # load first data frame self._read_frame(0) @staticmethod def _verify_units(eval_unit, expected_units): - if eval_unit.decode('utf-8') != expected_units: - errmsg = ("NETCDFReader currently assumes that the trajectory " - "was written in units of {0} instead of {1}".format( - eval_unit.decode('utf-8'), expected_units)) + if eval_unit.decode("utf-8") != expected_units: + errmsg = ( + "NETCDFReader currently assumes that the trajectory " + "was written in units of {0} instead of {1}".format( + eval_unit.decode("utf-8"), expected_units + ) + ) raise NotImplementedError(errmsg) @staticmethod def parse_n_atoms(filename, **kwargs): with scipy.io.netcdf_file(filename, mmap=None) as f: - n_atoms = f.dimensions['atom'] + n_atoms = f.dimensions["atom"] return n_atoms def _get_var_and_scale(self, variable, frame): @@ -646,28 +674,27 @@ def _read_frame(self, frame): # convention... for netcdf could also be a slice raise TypeError("frame must be a positive integer or zero") if frame >= self.n_frames or frame < 0: - raise IndexError("frame index must be 0 <= frame < {0}".format( - self.n_frames)) + raise IndexError( + "frame index must be 0 <= frame < {0}".format(self.n_frames) + ) # note: self.trjfile.variables['coordinates'].shape == (frames, n_atoms, 3) - ts._pos[:] = self._get_var_and_scale('coordinates', frame) + ts._pos[:] = self._get_var_and_scale("coordinates", frame) if self.has_time: - ts.time = self._get_var_and_scale('time', frame) + ts.time = self._get_var_and_scale("time", frame) if self.has_velocities: - ts._velocities[:] = self._get_var_and_scale('velocities', frame) + ts._velocities[:] = self._get_var_and_scale("velocities", frame) if self.has_forces: - ts._forces[:] = self._get_var_and_scale('forces', frame) + ts._forces[:] = self._get_var_and_scale("forces", frame) if self.periodic: unitcell = np.zeros(6) - unitcell[:3] = self._get_var_and_scale('cell_lengths', frame) - unitcell[3:] = self._get_var_and_scale('cell_angles', frame) + unitcell[:3] = self._get_var_and_scale("cell_lengths", frame) + unitcell[3:] = self._get_var_and_scale("cell_angles", frame) ts.dimensions = unitcell if self.convert_units: self.convert_pos_from_native(ts._pos) # in-place ! - self.convert_time_from_native( - ts.time) # in-place ! (hope this works...) + self.convert_time_from_native(ts.time) # in-place ! (hope this works...) if self.has_velocities: - self.convert_velocities_from_native(ts._velocities, - inplace=True) + self.convert_velocities_from_native(ts._velocities, inplace=True) if self.has_forces: self.convert_forces_from_native(ts._forces, inplace=True) if self.periodic: @@ -694,8 +721,8 @@ def _get_dt(self): AttributeError which triggers the default 1 ps return of dt(). """ try: - t1 = self.trjfile.variables['time'][1] - t0 = self.trjfile.variables['time'][0] + t1 = self.trjfile.variables["time"][1] + t0 = self.trjfile.variables["time"][0] except (IndexError, KeyError): raise AttributeError return t1 - t0 @@ -749,13 +776,13 @@ def Writer(self, filename, **kwargs): ------- :class:`NCDFWriter` """ - n_atoms = kwargs.pop('n_atoms', self.n_atoms) - kwargs.setdefault('remarks', self.remarks) - kwargs.setdefault('convert_units', self.convert_units) - kwargs.setdefault('velocities', self.has_velocities) - kwargs.setdefault('forces', self.has_forces) + n_atoms = kwargs.pop("n_atoms", self.n_atoms) + kwargs.setdefault("remarks", self.remarks) + kwargs.setdefault("convert_units", self.convert_units) + kwargs.setdefault("velocities", self.has_velocities) + kwargs.setdefault("forces", self.has_forces) for key in self.scale_factors: - kwargs.setdefault(f'scale_{key}', self.scale_factors[key]) + kwargs.setdefault(f"scale_{key}", self.scale_factors[key]) return NCDFWriter(filename, n_atoms, **kwargs) @@ -888,19 +915,32 @@ class NCDFWriter(base.WriterBase): """ - format = ['NC', 'NCDF'] + format = ["NC", "NCDF"] multiframe = True version = "1.0" - units = {'time': 'ps', - 'length': 'Angstrom', - 'velocity': 'Angstrom/ps', - 'force': 'kcal/(mol*Angstrom)'} - - def __init__(self, filename, n_atoms, remarks=None, convert_units=True, - velocities=False, forces=False, scale_time=None, - scale_cell_lengths=None, scale_cell_angles=None, - scale_coordinates=None, scale_velocities=None, - scale_forces=None, **kwargs): + units = { + "time": "ps", + "length": "Angstrom", + "velocity": "Angstrom/ps", + "force": "kcal/(mol*Angstrom)", + } + + def __init__( + self, + filename, + n_atoms, + remarks=None, + convert_units=True, + velocities=False, + forces=False, + scale_time=None, + scale_cell_lengths=None, + scale_cell_angles=None, + scale_coordinates=None, + scale_velocities=None, + scale_forces=None, + **kwargs, + ): self.filename = filename if n_atoms == 0: raise ValueError("NCDFWriter: no atoms in output trajectory") @@ -908,7 +948,9 @@ def __init__(self, filename, n_atoms, remarks=None, convert_units=True, # convert length and time to base units on the fly? self.convert_units = convert_units - self.remarks = remarks or "AMBER NetCDF format (MDAnalysis.coordinates.trj.NCDFWriter)" + self.remarks = ( + remarks or "AMBER NetCDF format (MDAnalysis.coordinates.trj.NCDFWriter)" + ) self._first_frame = True # signals to open trajectory self.trjfile = None # open on first write with _init_netcdf() @@ -917,16 +959,16 @@ def __init__(self, filename, n_atoms, remarks=None, convert_units=True, self.has_forces = forces self.scale_factors = { - 'time': scale_time, - 'cell_lengths': scale_cell_lengths, - 'cell_angles': scale_cell_angles, - 'coordinates': scale_coordinates, - 'velocities': scale_velocities, - 'forces': scale_forces} + "time": scale_time, + "cell_lengths": scale_cell_lengths, + "cell_angles": scale_cell_angles, + "coordinates": scale_coordinates, + "velocities": scale_velocities, + "forces": scale_forces, + } # NCDF standard enforces float scale_factors for value in self.scale_factors.values(): - if (value is not None) and ( - not isinstance(value, (float, np.floating))): + if (value is not None) and (not isinstance(value, (float, np.floating))): errmsg = f"scale_factor {value} is not a float" raise TypeError(errmsg) @@ -953,89 +995,90 @@ def _init_netcdf(self, periodic=True): """ if not self._first_frame: raise IOError( - errno.EIO, - "Attempt to write to closed file {0}".format(self.filename)) + errno.EIO, "Attempt to write to closed file {0}".format(self.filename) + ) if netCDF4: - ncfile = netCDF4.Dataset(self.filename, 'w', - format='NETCDF3_64BIT') + ncfile = netCDF4.Dataset(self.filename, "w", format="NETCDF3_64BIT") else: - ncfile = scipy.io.netcdf_file(self.filename, - mode='w', version=2, - maskandscale=False) - wmsg = ("Could not find netCDF4 module. Falling back to MUCH " - "slower scipy.io.netcdf implementation for writing.") + ncfile = scipy.io.netcdf_file( + self.filename, mode="w", version=2, maskandscale=False + ) + wmsg = ( + "Could not find netCDF4 module. Falling back to MUCH " + "slower scipy.io.netcdf implementation for writing." + ) logger.warning(wmsg) warnings.warn(wmsg) # Set global attributes. - setattr(ncfile, 'program', 'MDAnalysis.coordinates.TRJ.NCDFWriter') - setattr(ncfile, 'programVersion', MDAnalysis.__version__) - setattr(ncfile, 'Conventions', 'AMBER') - setattr(ncfile, 'ConventionVersion', '1.0') - setattr(ncfile, 'application', 'MDAnalysis') + setattr(ncfile, "program", "MDAnalysis.coordinates.TRJ.NCDFWriter") + setattr(ncfile, "programVersion", MDAnalysis.__version__) + setattr(ncfile, "Conventions", "AMBER") + setattr(ncfile, "ConventionVersion", "1.0") + setattr(ncfile, "application", "MDAnalysis") # Create dimensions - ncfile.createDimension('frame', - None) # unlimited number of steps (can append) - ncfile.createDimension('atom', - self.n_atoms) # number of atoms in system - ncfile.createDimension('spatial', 3) # number of spatial dimensions - ncfile.createDimension('cell_spatial', 3) # unitcell lengths - ncfile.createDimension('cell_angular', 3) # unitcell angles - ncfile.createDimension('label', 5) # needed for cell_angular + ncfile.createDimension("frame", None) # unlimited number of steps (can append) + ncfile.createDimension("atom", self.n_atoms) # number of atoms in system + ncfile.createDimension("spatial", 3) # number of spatial dimensions + ncfile.createDimension("cell_spatial", 3) # unitcell lengths + ncfile.createDimension("cell_angular", 3) # unitcell angles + ncfile.createDimension("label", 5) # needed for cell_angular # Create variables. - coords = ncfile.createVariable('coordinates', 'f4', - ('frame', 'atom', 'spatial')) - setattr(coords, 'units', 'angstrom') - if self.scale_factors['coordinates']: - coords.scale_factor = self.scale_factors['coordinates'] + coords = ncfile.createVariable( + "coordinates", "f4", ("frame", "atom", "spatial") + ) + setattr(coords, "units", "angstrom") + if self.scale_factors["coordinates"]: + coords.scale_factor = self.scale_factors["coordinates"] - spatial = ncfile.createVariable('spatial', 'c', ('spatial', )) - spatial[:] = np.asarray(list('xyz')) + spatial = ncfile.createVariable("spatial", "c", ("spatial",)) + spatial[:] = np.asarray(list("xyz")) - time = ncfile.createVariable('time', 'f4', ('frame',)) - setattr(time, 'units', 'picosecond') - if self.scale_factors['time']: - time.scale_factor = self.scale_factors['time'] + time = ncfile.createVariable("time", "f4", ("frame",)) + setattr(time, "units", "picosecond") + if self.scale_factors["time"]: + time.scale_factor = self.scale_factors["time"] self.periodic = periodic if self.periodic: - cell_lengths = ncfile.createVariable('cell_lengths', 'f8', - ('frame', 'cell_spatial')) - setattr(cell_lengths, 'units', 'angstrom') - if self.scale_factors['cell_lengths']: - cell_lengths.scale_factor = self.scale_factors['cell_lengths'] - - cell_spatial = ncfile.createVariable('cell_spatial', 'c', - ('cell_spatial', )) - cell_spatial[:] = np.asarray(list('abc')) - - cell_angles = ncfile.createVariable('cell_angles', 'f8', - ('frame', 'cell_angular')) - setattr(cell_angles, 'units', 'degree') - if self.scale_factors['cell_angles']: - cell_angles.scale_factor = self.scale_factors['cell_angles'] - - cell_angular = ncfile.createVariable('cell_angular', 'c', - ('cell_angular', 'label')) - cell_angular[:] = np.asarray([list('alpha'), list('beta '), list( - 'gamma')]) + cell_lengths = ncfile.createVariable( + "cell_lengths", "f8", ("frame", "cell_spatial") + ) + setattr(cell_lengths, "units", "angstrom") + if self.scale_factors["cell_lengths"]: + cell_lengths.scale_factor = self.scale_factors["cell_lengths"] + + cell_spatial = ncfile.createVariable("cell_spatial", "c", ("cell_spatial",)) + cell_spatial[:] = np.asarray(list("abc")) + + cell_angles = ncfile.createVariable( + "cell_angles", "f8", ("frame", "cell_angular") + ) + setattr(cell_angles, "units", "degree") + if self.scale_factors["cell_angles"]: + cell_angles.scale_factor = self.scale_factors["cell_angles"] + + cell_angular = ncfile.createVariable( + "cell_angular", "c", ("cell_angular", "label") + ) + cell_angular[:] = np.asarray([list("alpha"), list("beta "), list("gamma")]) # These properties are optional, and are specified on Writer creation if self.has_velocities: - velocs = ncfile.createVariable('velocities', 'f4', - ('frame', 'atom', 'spatial')) - setattr(velocs, 'units', 'angstrom/picosecond') - if self.scale_factors['velocities']: - velocs.scale_factor = self.scale_factors['velocities'] + velocs = ncfile.createVariable( + "velocities", "f4", ("frame", "atom", "spatial") + ) + setattr(velocs, "units", "angstrom/picosecond") + if self.scale_factors["velocities"]: + velocs.scale_factor = self.scale_factors["velocities"] if self.has_forces: - forces = ncfile.createVariable('forces', 'f4', - ('frame', 'atom', 'spatial')) - setattr(forces, 'units', 'kilocalorie/mole/angstrom') - if self.scale_factors['forces']: - forces.scale_factor = self.scale_factors['forces'] + forces = ncfile.createVariable("forces", "f4", ("frame", "atom", "spatial")) + setattr(forces, "units", "kilocalorie/mole/angstrom") + if self.scale_factors["forces"]: + forces.scale_factor = self.scale_factors["forces"] # Important for netCDF4! Disable maskandscale for created variables! # Won't work if called before variable creation! @@ -1090,7 +1133,8 @@ def _write_next_frame(self, ag): if ts.n_atoms != self.n_atoms: raise IOError( - "NCDFWriter: Timestep does not have the correct number of atoms") + "NCDFWriter: Timestep does not have the correct number of atoms" + ) if self.trjfile is None: # first time step: analyze data and open trajectory accordingly @@ -1147,35 +1191,35 @@ def _write_next_timestep(self, ts): # write step # coordinates - self._set_frame_var_and_scale('coordinates', pos) + self._set_frame_var_and_scale("coordinates", pos) # time - self._set_frame_var_and_scale('time', time) + self._set_frame_var_and_scale("time", time) # unitcell if self.periodic: # cell lengths - self._set_frame_var_and_scale('cell_lengths', unitcell[:3]) + self._set_frame_var_and_scale("cell_lengths", unitcell[:3]) - self._set_frame_var_and_scale('cell_angles', unitcell[3:]) + self._set_frame_var_and_scale("cell_angles", unitcell[3:]) # velocities if self.has_velocities: velocities = ts._velocities if self.convert_units: velocities = self.convert_velocities_to_native( - velocities, inplace=False) + velocities, inplace=False + ) - self._set_frame_var_and_scale('velocities', velocities) + self._set_frame_var_and_scale("velocities", velocities) # forces if self.has_forces: forces = ts._forces if self.convert_units: - forces = self.convert_forces_to_native( - forces, inplace=False) + forces = self.convert_forces_to_native(forces, inplace=False) - self._set_frame_var_and_scale('forces', forces) + self._set_frame_var_and_scale("forces", forces) self.trjfile.sync() self.curr_frame += 1 @@ -1247,10 +1291,9 @@ class NCDFPicklable(scipy.io.netcdf_file): .. _`scipy netcdf API documentation`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.netcdf_file.html """ + def __getstate__(self): - return (self.filename, self.use_mmap, self.version_byte, - self.maskandscale) + return (self.filename, self.use_mmap, self.version_byte, self.maskandscale) def __setstate__(self, args): - self.__init__(args[0], mmap=args[1], version=args[2], - maskandscale=args[3]) + self.__init__(args[0], mmap=args[1], version=args[2], maskandscale=args[3]) diff --git a/package/MDAnalysis/coordinates/TRR.py b/package/MDAnalysis/coordinates/TRR.py index 850825915c..f6581ee597 100644 --- a/package/MDAnalysis/coordinates/TRR.py +++ b/package/MDAnalysis/coordinates/TRR.py @@ -57,10 +57,9 @@ class TRRWriter(XDRBaseWriter): """ - format = 'TRR' + format = "TRR" multiframe = True - units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps', - 'force': 'kJ/(mol*nm)'} + units = {"time": "ps", "length": "nm", "velocity": "nm/ps", "force": "kJ/(mol*nm)"} _file = TRRFile def _write_next_frame(self, ag): @@ -117,7 +116,7 @@ def _write_next_frame(self, ag): time = ts.time else: time = self._dt * ts.frame - step = ts.data.get('step', ts.frame) + step = ts.data.get("step", ts.frame) if self._convert_units: dimensions = self.convert_dimensions_to_unitcell(ts, inplace=False) @@ -125,11 +124,10 @@ def _write_next_frame(self, ag): box = triclinic_vectors(dimensions) lmbda = 0 - if 'lambda' in ts.data: - lmbda = ts.data['lambda'] + if "lambda" in ts.data: + lmbda = ts.data["lambda"] - self._xdr.write(xyz, velo, forces, box, step, time, lmbda, - self.n_atoms) + self._xdr.write(xyz, velo, forces, box, step, time, lmbda, self.n_atoms) class TRRReader(XDRBaseReader): @@ -149,22 +147,22 @@ class TRRReader(XDRBaseReader): offsets. """ - format = 'TRR' - units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps', - 'force': 'kJ/(mol*nm)'} + + format = "TRR" + units = {"time": "ps", "length": "nm", "velocity": "nm/ps", "force": "kJ/(mol*nm)"} _writer = TRRWriter _file = TRRFile def _read_next_timestep(self, ts=None): """copy next frame into timestep - + versionadded:: 2.4.0 TRRReader implements this method so that it can use read_direct_xvf to read the data directly into the timestep rather than copying it from a temporary array. """ if self._frame == self.n_frames - 1: - raise IOError(errno.EIO, 'trying to go over trajectory limit') + raise IOError(errno.EIO, "trying to go over trajectory limit") if ts is None: ts = self.ts # allocate arrays to read into, will set to proper values @@ -185,7 +183,7 @@ def _frame_to_ts(self, frame, ts): else: ts.time = self._frame * dt ts.frame = self._frame - ts.data['step'] = frame.step + ts.data["step"] = frame.step ts.has_positions = frame.hasx ts.has_velocities = frame.hasv @@ -220,6 +218,6 @@ def _frame_to_ts(self, frame, ts): if self.convert_units: self.convert_forces_from_native(ts.forces) - ts.data['lambda'] = frame.lmbda + ts.data["lambda"] = frame.lmbda return ts diff --git a/package/MDAnalysis/coordinates/TRZ.py b/package/MDAnalysis/coordinates/TRZ.py index 82ada24e6a..0bebf57092 100644 --- a/package/MDAnalysis/coordinates/TRZ.py +++ b/package/MDAnalysis/coordinates/TRZ.py @@ -93,7 +93,7 @@ class TRZReader(base.ReaderBase): format = "TRZ" - units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps'} + units = {"time": "ps", "length": "nm", "velocity": "nm/ps"} @store_init_arguments def __init__(self, trzfilename, n_atoms=None, **kwargs): @@ -114,84 +114,93 @@ def __init__(self, trzfilename, n_atoms=None, **kwargs): If `n_atoms` or the number of atoms in the topology file do not match the number of atoms in the trajectory. """ - wmsg = ("The TRZ reader is deprecated and will be removed in " - "MDAnalysis version 3.0.0") + wmsg = ( + "The TRZ reader is deprecated and will be removed in " + "MDAnalysis version 3.0.0" + ) warnings.warn(wmsg, DeprecationWarning) - super(TRZReader, self).__init__(trzfilename, **kwargs) + super(TRZReader, self).__init__(trzfilename, **kwargs) if n_atoms is None: - raise ValueError('TRZReader requires the n_atoms keyword') + raise ValueError("TRZReader requires the n_atoms keyword") - self.trzfile = util.anyopen(self.filename, 'rb') + self.trzfile = util.anyopen(self.filename, "rb") self._cache = dict() self._n_atoms = n_atoms self._read_trz_header() - self.ts = Timestep(self.n_atoms, - velocities=True, - forces=self.has_force, - reader=self, - **self._ts_kwargs) + self.ts = Timestep( + self.n_atoms, + velocities=True, + forces=self.has_force, + reader=self, + **self._ts_kwargs + ) # structured dtype of a single trajectory frame - readarg = str(n_atoms) + ' angstroms) @@ -245,7 +255,7 @@ def n_atoms(self): return self._n_atoms @property - @cached('n_frames') + @cached("n_frames") def n_frames(self): """Total number of frames in a trajectory""" try: @@ -262,9 +272,13 @@ def _read_trz_n_frames(self, trzfile): fsize = os.fstat(trzfile.fileno()).st_size # size of file in bytes if not (fsize - self._headerdtype.itemsize) % self._dtype.itemsize == 0: - raise IOError("Trajectory has incomplete frames") # check that division is sane + raise IOError( + "Trajectory has incomplete frames" + ) # check that division is sane - nframes = int((fsize - self._headerdtype.itemsize) / self._dtype.itemsize) # returns long int otherwise + nframes = int( + (fsize - self._headerdtype.itemsize) / self._dtype.itemsize + ) # returns long int otherwise return nframes @@ -294,20 +308,20 @@ def _get_dt(self): self._read_frame(curr_frame) @property - @cached('delta') + @cached("delta") def delta(self): """MD integration timestep""" return self.dt / self.skip_timestep @property - @cached('skip_timestep') + @cached("skip_timestep") def skip_timestep(self): """Timesteps between trajectory frames""" curr_frame = self.ts.frame try: - t0 = self.ts.data['frame'] + t0 = self.ts.data["frame"] self.next() - t1 = self.ts.data['frame'] + t1 = self.ts.data["frame"] skip_timestep = t1 - t0 except StopIteration: return 0 @@ -365,13 +379,13 @@ def _reopen(self): def open_trajectory(self): """Open the trajectory file""" if self.trzfile is not None: - raise IOError(errno.EALREADY, 'TRZ file already opened', self.filename) + raise IOError(errno.EALREADY, "TRZ file already opened", self.filename) if not os.path.exists(self.filename): - raise IOError(errno.ENOENT, 'TRZ file not found', self.filename) + raise IOError(errno.ENOENT, "TRZ file not found", self.filename) - self.trzfile = util.anyopen(self.filename, 'rb') + self.trzfile = util.anyopen(self.filename, "rb") - #Reset ts + # Reset ts ts = self.ts ts.frame = -1 @@ -403,12 +417,12 @@ class TRZWriter(base.WriterBase): and will be removed in version 3.0.0. """ - format = 'TRZ' + format = "TRZ" multiframe = True - units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps'} + units = {"time": "ps", "length": "nm", "velocity": "nm/ps"} - def __init__(self, filename, n_atoms, title='TRZ', convert_units=True): + def __init__(self, filename, n_atoms, title="TRZ", convert_units=True): """Create a TRZWriter Parameters @@ -423,8 +437,10 @@ def __init__(self, filename, n_atoms, title='TRZ', convert_units=True): convert_units : bool (optional) units are converted to the MDAnalysis base format; [``True``] """ - wmsg = ("The TRZ writer is deprecated and will be removed in " - "MDAnalysis version 3.0.0") + wmsg = ( + "The TRZ writer is deprecated and will be removed in " + "MDAnalysis version 3.0.0" + ) warnings.warn(wmsg, DeprecationWarning) self.filename = filename @@ -439,61 +455,71 @@ def __init__(self, filename, n_atoms, title='TRZ', convert_units=True): self.convert_units = convert_units - self.trzfile = util.anyopen(self.filename, 'wb') + self.trzfile = util.anyopen(self.filename, "wb") self._writeheader(title) - floatsize = str(n_atoms) + ' int: return self.n_frames @@ -695,8 +704,9 @@ def parse_n_atoms(cls, filename, **kwargs): NotImplementedError when the number of atoms can't be deduced """ - raise NotImplementedError("{} cannot deduce the number of atoms" - "".format(cls.__name__)) + raise NotImplementedError( + "{} cannot deduce the number of atoms" "".format(cls.__name__) + ) def next(self) -> Timestep: """Forward one step to next frame.""" @@ -766,7 +776,8 @@ def Writer(self, filename, **kwargs): raise NotImplementedError( "Sorry, there is no Writer for this format in MDAnalysis. " "Please file an enhancement request at " - "https://github.com/MDAnalysis/mdanalysis/issues") + "https://github.com/MDAnalysis/mdanalysis/issues" + ) def OtherWriter(self, filename, **kwargs): """Returns a writer appropriate for *filename*. @@ -780,10 +791,10 @@ def OtherWriter(self, filename, **kwargs): :meth:`Reader.Writer` and :func:`MDAnalysis.Writer` """ - kwargs['n_atoms'] = self.n_atoms # essential - kwargs.setdefault('start', self.frame) + kwargs["n_atoms"] = self.n_atoms # essential + kwargs.setdefault("start", self.frame) try: - kwargs.setdefault('dt', self.dt) + kwargs.setdefault("dt", self.dt) except KeyError: pass return core.writer(filename, **kwargs) @@ -798,7 +809,7 @@ def _read_next_timestep(self, ts=None): ... def __iter__(self): - """ Iterate over trajectory frames. """ + """Iterate over trajectory frames.""" self._reopen() return self @@ -808,14 +819,16 @@ def _reopen(self): Calling next after this should return the first frame """ - pass # pylint: disable=unnecessary-pass + pass # pylint: disable=unnecessary-pass def _apply_limits(self, frame): if frame < 0: frame += len(self) if frame < 0 or frame >= len(self): - raise IndexError("Index {} exceeds length of trajectory ({})." - "".format(frame, len(self))) + raise IndexError( + "Index {} exceeds length of trajectory ({})." + "".format(frame, len(self)) + ) return frame def __getitem__(self, frame): @@ -843,19 +856,24 @@ def __getitem__(self, frame): return FrameIteratorIndices(self, frame) elif isinstance(frame, slice): start, stop, step = self.check_slice_indices( - frame.start, frame.stop, frame.step) + frame.start, frame.stop, frame.step + ) if start == 0 and stop == len(self) and step == 1: return FrameIteratorAll(self) else: return FrameIteratorSliced(self, frame) else: - raise TypeError("Trajectories must be an indexed using an integer," - " slice or list of indices") + raise TypeError( + "Trajectories must be an indexed using an integer," + " slice or list of indices" + ) def _read_frame(self, frame): """Move to *frame* and fill timestep with data.""" - raise TypeError("{0} does not support direct frame indexing." - "".format(self.__class__.__name__)) + raise TypeError( + "{0} does not support direct frame indexing." + "".format(self.__class__.__name__) + ) # Example implementation in the DCDReader: # self._jump_to_frame(frame) # ts = self.ts @@ -941,18 +959,18 @@ def check_slice_indices(self, start, stop, step): """ - slice_dict = {'start': start, 'stop': stop, 'step': step} + slice_dict = {"start": start, "stop": stop, "step": step} for varname, var in slice_dict.items(): if isinstance(var, numbers.Integral): slice_dict[varname] = int(var) - elif (var is None): + elif var is None: pass else: raise TypeError("{0} is not an integer".format(varname)) - start = slice_dict['start'] - stop = slice_dict['stop'] - step = slice_dict['step'] + start = slice_dict["start"] + stop = slice_dict["stop"] + step = slice_dict["step"] if step == 0: raise ValueError("Step size is zero") @@ -981,19 +999,22 @@ def check_slice_indices(self, start, stop, step): return start, stop, step def __repr__(self): - return ("<{cls} {fname} with {nframes} frames of {natoms} atoms>" - "".format( + return "<{cls} {fname} with {nframes} frames of {natoms} atoms>" "".format( cls=self.__class__.__name__, fname=self.filename, nframes=self.n_frames, - natoms=self.n_atoms - )) - - def timeseries(self, asel: Optional['AtomGroup']=None, - atomgroup: Optional['Atomgroup']=None, - start: Optional[int]=None, stop: Optional[int]=None, - step: Optional[int]=None, - order: Optional[str]='fac') -> np.ndarray: + natoms=self.n_atoms, + ) + + def timeseries( + self, + asel: Optional["AtomGroup"] = None, + atomgroup: Optional["Atomgroup"] = None, + start: Optional[int] = None, + stop: Optional[int] = None, + step: Optional[int] = None, + order: Optional[str] = "fac", + ) -> np.ndarray: """Return a subset of coordinate data for an AtomGroup Parameters @@ -1037,7 +1058,8 @@ def timeseries(self, asel: Optional['AtomGroup']=None, warnings.warn( "asel argument to timeseries will be renamed to" "'atomgroup' in 3.0, see #3911", - category=DeprecationWarning) + category=DeprecationWarning, + ) if atomgroup: raise ValueError("Cannot provide both asel and atomgroup kwargs") atomgroup = asel @@ -1046,8 +1068,7 @@ def timeseries(self, asel: Optional['AtomGroup']=None, if atomgroup is not None: if len(atomgroup) == 0: - raise ValueError( - "Timeseries requires at least one atom to analyze") + raise ValueError("Timeseries requires at least one atom to analyze") atom_numbers = atomgroup.indices natoms = len(atom_numbers) else: @@ -1060,28 +1081,34 @@ def timeseries(self, asel: Optional['AtomGroup']=None, coordinates[i, :] = ts.positions[atom_numbers] # switch axes around - default_order = 'fac' + default_order = "fac" if order != default_order: try: newidx = [default_order.index(i) for i in order] except ValueError: - raise ValueError(f"Unrecognized order key in {order}, " - "must be permutation of 'fac'") + raise ValueError( + f"Unrecognized order key in {order}, " + "must be permutation of 'fac'" + ) try: coordinates = np.moveaxis(coordinates, newidx, [0, 1, 2]) except ValueError: - errmsg = ("Repeated or missing keys passed to argument " - f"`order`: {order}, each key must be used once") + errmsg = ( + "Repeated or missing keys passed to argument " + f"`order`: {order}, each key must be used once" + ) raise ValueError(errmsg) return coordinates -# TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def add_auxiliary(self, - aux_spec: Union[str, Dict[str, str]] = None, - auxdata: Union[str, AuxReader] = None, - format: str = None, - **kwargs) -> None: + # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 + def add_auxiliary( + self, + aux_spec: Union[str, Dict[str, str]] = None, + auxdata: Union[str, AuxReader] = None, + format: str = None, + **kwargs, + ) -> None: """Add auxiliary data to be read alongside trajectory. Auxiliary data may be any data timeseries from the trajectory @@ -1144,8 +1171,9 @@ def add_auxiliary(self, the :ref:`Auxiliary API`. """ if auxdata is None: - raise ValueError("No input `auxdata` specified, but it needs " - "to be provided.") + raise ValueError( + "No input `auxdata` specified, but it needs " "to be provided." + ) if type(auxdata) not in list(_AUXREADERS.values()): # i.e. if auxdata is a file, not an instance of an AuxReader reader_type = get_auxreader_for(auxdata) @@ -1169,11 +1197,11 @@ def remove_auxiliary(self, auxname): @property def aux_list(self): - """ Lists the names of added auxiliary data. """ + """Lists the names of added auxiliary data.""" return self._auxs.keys() def _check_for_aux(self, auxname): - """ Check for the existance of an auxiliary *auxname*. If present, + """Check for the existance of an auxiliary *auxname*. If present, return the AuxReader; if not, raise ValueError """ if auxname in self.aux_list: @@ -1182,7 +1210,7 @@ def _check_for_aux(self, auxname): raise ValueError("No auxiliary named {name}".format(name=auxname)) def next_as_aux(self, auxname): - """ Move to the next timestep for which there is at least one step from + """Move to the next timestep for which there is at least one step from the auxiliary *auxname* within the cutoff specified in *auxname*. This allows progression through the trajectory without encountering @@ -1214,7 +1242,7 @@ def next_as_aux(self, auxname): raise StopIteration # some readers set self._frame to -1, rather than self.frame, on # _reopen; catch here or doesn't read first frame - while self.frame != next_frame or getattr(self, '_frame', 0) == -1: + while self.frame != next_frame or getattr(self, "_frame", 0) == -1: # iterate trajectory until frame is reached ts = self.next() return ts @@ -1237,9 +1265,8 @@ def iter_as_aux(self, auxname): except StopIteration: return - def iter_auxiliary(self, auxname, start=None, stop=None, step=None, - selected=None): - """ Iterate through the auxiliary *auxname* independently of the trajectory. + def iter_auxiliary(self, auxname, start=None, stop=None, step=None, selected=None): + """Iterate through the auxiliary *auxname* independently of the trajectory. Will iterate over the specified steps of the auxiliary (defaults to all steps). Allows to access all values in an auxiliary, including those out @@ -1292,7 +1319,7 @@ def get_aux_attribute(self, auxname, attrname): return getattr(aux, attrname) def set_aux_attribute(self, auxname, attrname, new): - """ Set the value of *attrname* in the auxiliary *auxname*. + """Set the value of *attrname* in the auxiliary *auxname*. Parameters ---------- @@ -1309,13 +1336,13 @@ def set_aux_attribute(self, auxname, attrname, new): :meth:`rename_aux` - to change the *auxname* attribute """ aux = self._check_for_aux(auxname) - if attrname == 'auxname': + if attrname == "auxname": self.rename_aux(auxname, new) else: setattr(aux, attrname, new) def rename_aux(self, auxname, new): - """ Change the name of the auxiliary *auxname* to *new*. + """Change the name of the auxiliary *auxname* to *new*. Provided there is not already an auxiliary named *new*, the auxiliary name will be changed in ts.aux namespace, the trajectory's @@ -1335,8 +1362,9 @@ def rename_aux(self, auxname, new): """ aux = self._check_for_aux(auxname) if new in self.aux_list: - raise ValueError("Auxiliary data with name {name} already " - "exists".format(name=new)) + raise ValueError( + "Auxiliary data with name {name} already " "exists".format(name=new) + ) aux.auxname = new self._auxs[new] = self._auxs.pop(auxname) setattr(self.ts.aux, new, self.ts.aux[auxname]) @@ -1373,7 +1401,7 @@ def get_aux_descriptions(self, auxnames=None): @property def transformations(self): - """ Returns the list of transformations""" + """Returns the list of transformations""" return self._transformations @transformations.setter @@ -1427,18 +1455,19 @@ def add_transformations(self, *transformations): try: self.transformations = transformations except ValueError: - errmsg = ("Can't add transformations again. Please create a new " - "Universe object") + errmsg = ( + "Can't add transformations again. Please create a new " + "Universe object" + ) raise ValueError(errmsg) from None else: self.ts = self._apply_transformations(self.ts) - # call reader here to apply the newly added transformation on the # current loaded frame? def _apply_transformations(self, ts): - """Applies all the transformations given by the user """ + """Applies all the transformations given by the user""" for transform in self.transformations: ts = transform(ts) @@ -1474,6 +1503,7 @@ class ReaderBase(ProtoReader): Removed deprecated flags functionality, use convert_units kwarg instead """ + @store_init_arguments def __init__(self, filename, convert_units=True, **kwargs): super(ReaderBase, self).__init__() @@ -1485,7 +1515,7 @@ def __init__(self, filename, convert_units=True, **kwargs): self.convert_units = convert_units ts_kwargs = {} - for att in ('dt', 'time_offset'): + for att in ("dt", "time_offset"): try: val = kwargs[att] except KeyError: @@ -1538,14 +1568,14 @@ def __init__(cls, name, bases, classdict): try: # grab the string which describes this format # could be either 'PDB' or ['PDB', 'ENT'] for multiple formats - fmt = asiterable(classdict['format']) + fmt = asiterable(classdict["format"]) except KeyError: # not required however pass else: # does the Writer support single and multiframe writing? - single = classdict.get('singleframe', True) - multi = classdict.get('multiframe', False) + single = classdict.get("singleframe", True) + multi = classdict.get("multiframe", False) if single: for f in fmt: @@ -1612,7 +1642,9 @@ def __del__(self): def __repr__(self): try: - return "< {0!s} {1!r} for {2:d} atoms >".format(self.__class__.__name__, self.filename, self.n_atoms) + return "< {0!s} {1!r} for {2:d} atoms >".format( + self.__class__.__name__, self.filename, self.n_atoms + ) except (TypeError, AttributeError): # no trajectory loaded yet or a Writer that does not need e.g. # self.n_atoms @@ -1659,6 +1691,7 @@ class SingleFrameReaderBase(ProtoReader): Fixed a typo in the attribute assignment (`self.atom` → `self.atoms`), which may affect subclasses relying on this value. """ + _err = "{0} only contains a single frame" @store_init_arguments @@ -1672,7 +1705,7 @@ def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): self.n_atoms = n_atoms ts_kwargs = {} - for att in ('dt', 'time_offset'): + for att in ("dt", "time_offset"): try: val = kwargs[att] except KeyError: @@ -1747,7 +1780,7 @@ def close(self): pass def add_transformations(self, *transformations): - """ Add all transformations to be applied to the trajectory. + """Add all transformations to be applied to the trajectory. This function take as list of transformations as an argument. These transformations are functions that will be called by the Reader and given @@ -1773,17 +1806,17 @@ def add_transformations(self, *transformations): -------- :mod:`MDAnalysis.transformations` """ - #Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` - #to avoid unintended behaviour where the coordinates of each frame are transformed - #multiple times when iterating over the trajectory. - #In this method, the trajectory is modified all at once and once only. + # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` + # to avoid unintended behaviour where the coordinates of each frame are transformed + # multiple times when iterating over the trajectory. + # In this method, the trajectory is modified all at once and once only. super(SingleFrameReaderBase, self).add_transformations(*transformations) for transform in self.transformations: self.ts = transform(self.ts) def _apply_transformations(self, ts): - """ Applies the transformations to the timestep.""" + """Applies the transformations to the timestep.""" # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` # to avoid applying the same transformations multiple times on each frame @@ -1791,16 +1824,17 @@ def _apply_transformations(self, ts): def range_length(start, stop, step): - if (step > 0 and start < stop): + if step > 0 and start < stop: # We go from a lesser number to a larger one. return int(1 + (stop - 1 - start) // step) - elif (step < 0 and start > stop): + elif step < 0 and start > stop: # We count backward from a larger number to a lesser one. return int(1 + (start - 1 - stop) // (-step)) else: # The range is empty. return 0 + # Verbatim copy of code from converters/base.py # Needed to avoid circular imports before removal in # MDAnalysis 3.0.0 @@ -1810,7 +1844,7 @@ class _Convertermeta(type): def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - fmt = asiterable(classdict['lib']) + fmt = asiterable(classdict["lib"]) except KeyError: pass else: @@ -1833,10 +1867,12 @@ class ConverterBase(IOBase, metaclass=_Convertermeta): """ def __init_subclass__(cls): - wmsg = ("ConverterBase moved from coordinates.base." - "ConverterBase to converters.base.ConverterBase " - "and will be removed from coordinates.base " - "in MDAnalysis release 3.0.0") + wmsg = ( + "ConverterBase moved from coordinates.base." + "ConverterBase to converters.base.ConverterBase " + "and will be removed from coordinates.base " + "in MDAnalysis release 3.0.0" + ) warnings.warn(wmsg, DeprecationWarning, stacklevel=2) def __repr__(self): diff --git a/package/MDAnalysis/coordinates/chain.py b/package/MDAnalysis/coordinates/chain.py index 245b760acd..755aa5d0c5 100644 --- a/package/MDAnalysis/coordinates/chain.py +++ b/package/MDAnalysis/coordinates/chain.py @@ -105,28 +105,40 @@ def filter_times(times, dt): """ # Special cases if len(times) == 1: - return [0, ] + return [ + 0, + ] elif len(times) == 2: if times[0][0] < times[1][0]: return [0, 1] elif np.allclose(times[0][0], times[1][0]): - return [1, ] + return [ + 1, + ] else: - return [0, ] + return [ + 0, + ] if np.unique(times).size == 2: - return [len(times) - 1, ] + return [ + len(times) - 1, + ] # more then 2 unique time entries - used_idx = [0, ] + used_idx = [ + 0, + ] - for i, (first, middle, last) in enumerate(zip(times[:-2], times[1:-1], times[2:]), start=1): + for i, (first, middle, last) in enumerate( + zip(times[:-2], times[1:-1], times[2:]), start=1 + ): if np.allclose(first[0], middle[0]): used_idx[-1] = i elif not np.allclose(middle[1] - middle[0], dt): if (middle[0] <= first[1]) and (last[0] <= middle[1]): used_idx.append(i) - elif (middle[0] <= first[1]): + elif middle[0] <= first[1]: used_idx.append(i) # take care of first special case @@ -147,15 +159,19 @@ def check_allowed_filetypes(readers, allowed): allowed : list of allowed formats """ classname = type(readers[0]) - only_one_reader = np.all([isinstance(r, classname) for r in readers]) + only_one_reader = np.all([isinstance(r, classname) for r in readers]) if not only_one_reader: readernames = [type(r) for r in readers] - raise ValueError("ChainReader: continuous=true only supported" - " when all files are using the same reader. " - "Found: {}".format(readernames)) + raise ValueError( + "ChainReader: continuous=true only supported" + " when all files are using the same reader. " + "Found: {}".format(readernames) + ) if readers[0].format not in allowed: - raise NotImplementedError("ChainReader: continuous=True only " - "supported for formats: {}".format(allowed)) + raise NotImplementedError( + "ChainReader: continuous=True only " + "supported for formats: {}".format(allowed) + ) class ChainReader(base.ReaderBase): @@ -215,11 +231,13 @@ class ChainReader(base.ReaderBase): current timestep is retained. """ - format = 'CHAIN' + + format = "CHAIN" @store_init_arguments - def __init__(self, filenames, skip=1, dt=None, continuous=False, - convert_units=True, **kwargs): + def __init__( + self, filenames, skip=1, dt=None, continuous=False, convert_units=True, **kwargs + ): """Set up the chain reader. Parameters @@ -256,19 +274,19 @@ def __init__(self, filenames, skip=1, dt=None, continuous=False, unchanged """ - super(ChainReader, self).__init__(filename='CHAIN', - skip=skip, - convert_units=convert_units, - dt=dt, - **kwargs) + super(ChainReader, self).__init__( + filename="CHAIN", skip=skip, convert_units=convert_units, dt=dt, **kwargs + ) filenames = asiterable(filenames) # Override here because single frame readers handle this argument as a # kwarg to a timestep which behaves differently if dt is present or not. if dt is not None: - kwargs['dt'] = dt - self.readers = [core.reader(filename, convert_units=convert_units, **kwargs) - for filename in filenames] + kwargs["dt"] = dt + self.readers = [ + core.reader(filename, convert_units=convert_units, **kwargs) + for filename in filenames + ] # Iterate through all filenames, appending NoneType None for ndarrays self.filenames = [] for fn in filenames: @@ -284,7 +302,7 @@ def __init__(self, filenames, skip=1, dt=None, continuous=False, self.__active_reader_index = 0 self.skip = skip - self.n_atoms = self._get_same('n_atoms') + self.n_atoms = self._get_same("n_atoms") # Translation between virtual frames and frames in individual # trajectories. Assumes that individual trajectories i contain frames @@ -297,25 +315,26 @@ def __init__(self, filenames, skip=1, dt=None, continuous=False, # trajectory i and local frame f (i.e. readers[i][f] will correspond to # ChainReader[k]). # build map 'start_frames', which is used by _get_local_frame() - n_frames = self._get('n_frames') + n_frames = self._get("n_frames") # [0]: frames are 0-indexed internally # (see Timestep.check_slice_indices()) self._start_frames = np.cumsum([0] + n_frames) self.n_frames = np.sum(n_frames) - self.dts = np.array(self._get('dt')) + self.dts = np.array(self._get("dt")) self.total_times = self.dts * n_frames # calculate new start_frames to have a time continuous trajectory. if continuous: - check_allowed_filetypes(self.readers, ['XTC', 'TRR', 'LAMMPSDUMP', - 'TRC']) + check_allowed_filetypes(self.readers, ["XTC", "TRR", "LAMMPSDUMP", "TRC"]) if np.any(np.array(n_frames) == 1): - raise RuntimeError("ChainReader: Need at least two frames in " - "every trajectory with continuous=True") + raise RuntimeError( + "ChainReader: Need at least two frames in " + "every trajectory with continuous=True" + ) # TODO: allow floating point precision in dt check - dt = self._get_same('dt') - n_frames = np.asarray(self._get('n_frames')) + dt = self._get_same("dt") + n_frames = np.asarray(self._get("n_frames")) self.dts = np.ones(self.dts.shape) * dt # the sorting needs to happen on two levels. The first major level @@ -347,7 +366,9 @@ def __init__(self, filenames, skip=1, dt=None, continuous=False, self.total_times = self.dts[used_idx] * n_frames[used_idx] # rebuild lookup table - sf = [0, ] + sf = [ + 0, + ] n_frames = 0 for r1, r2 in zip(self.readers[:-1], self.readers[1:]): r2[0], r1[0] @@ -360,8 +381,10 @@ def __init__(self, filenames, skip=1, dt=None, continuous=False, # check for interleaving r1[1] if r1_start_time < start_time < r1.time: - raise RuntimeError("ChainReader: Interleaving not supported " - "with continuous=True.") + raise RuntimeError( + "ChainReader: Interleaving not supported " + "with continuous=True." + ) # find end where trajectory was restarted from for ts in r1[::-1]: @@ -387,9 +410,11 @@ def _format_hint(thing): .. versionadded:: 1.0.0 """ - return (not isinstance(thing, np.ndarray) and - util.iterable(thing) and - not util.isstream(thing)) + return ( + not isinstance(thing, np.ndarray) + and util.iterable(thing) + and not util.isstream(thing) + ) def _get_local_frame(self, k) -> Tuple[int, int]: """Find trajectory index and trajectory frame for chained frame `k`. @@ -435,16 +460,16 @@ def _get_local_frame(self, k) -> Tuple[int, int]: def __getstate__(self): state = self.__dict__.copy() # save ts temporarily otherwise it will be changed during rewinding. - state['ts'] = self.ts.__deepcopy__() + state["ts"] = self.ts.__deepcopy__() # the ts.frame of each reader is set to the chained frame index during # iteration, thus we need to rewind the readers that have been used. # PR #2723 - for reader in state['readers'][:self.__active_reader_index + 1]: + for reader in state["readers"][: self.__active_reader_index + 1]: reader.rewind() # retrieve the current ts - self.ts = state['ts'] + self.ts = state["ts"] return state def __setstate__(self, state): @@ -538,15 +563,19 @@ def _get_same(self, attr): value = values[0] if not np.allclose(values, value): bad_traj = np.array(self.filenames)[values != value] - raise ValueError("The following trajectories do not have the correct {0} " - " ({1}):\n{2}".format(attr, value, bad_traj)) + raise ValueError( + "The following trajectories do not have the correct {0} " + " ({1}):\n{2}".format(attr, value, bad_traj) + ) return value def __activate_reader(self, i): """Make reader `i` the active reader.""" # private method, not to be used by user to avoid a total mess if not (0 <= i < len(self.readers)): - raise IndexError("Reader index must be 0 <= i < {0:d}".format(len(self.readers))) + raise IndexError( + "Reader index must be 0 <= i < {0:d}".format(len(self.readers)) + ) self.__active_reader_index = i self.filename = self.filenames[i] @@ -600,24 +629,34 @@ def _read_next_timestep(self, ts=None): def _reopen(self): """Internal method: Rewind trajectories themselves and trj pointer.""" self.__current_frame = -1 - self._apply('rewind') + self._apply("rewind") def close(self): - self._apply('close') + self._apply("close") def __repr__(self): if len(self.filenames) > 3: - fname = (os.path.basename(self.filenames[0]) - if self.filenames[0] else "numpy.ndarray") + fname = ( + os.path.basename(self.filenames[0]) + if self.filenames[0] + else "numpy.ndarray" + ) fnames = "{fname} and {nfnames} more".format( - fname=fname, - nfnames=len(self.filenames) - 1) + fname=fname, nfnames=len(self.filenames) - 1 + ) else: - fnames = ", ".join([os.path.basename(fn) if fn else "numpy.ndarray" - for fn in self.filenames]) - return ("<{clsname} containing {fname} with {nframes} frames of {natoms} atoms>" - "".format( - clsname=self.__class__.__name__, - fname=fnames, - nframes=self.n_frames, - natoms=self.n_atoms)) + fnames = ", ".join( + [ + os.path.basename(fn) if fn else "numpy.ndarray" + for fn in self.filenames + ] + ) + return ( + "<{clsname} containing {fname} with {nframes} frames of {natoms} atoms>" + "".format( + clsname=self.__class__.__name__, + fname=fnames, + nframes=self.n_frames, + natoms=self.n_atoms, + ) + ) diff --git a/package/MDAnalysis/coordinates/memory.py b/package/MDAnalysis/coordinates/memory.py index 288ceceac3..1e0088a718 100644 --- a/package/MDAnalysis/coordinates/memory.py +++ b/package/MDAnalysis/coordinates/memory.py @@ -249,12 +249,19 @@ class MemoryReader(base.ProtoReader): :meth:`MemoryReader.timeseries` has now been removed. """ - format = 'MEMORY' - - def __init__(self, coordinate_array, order='fac', - dimensions=None, dt=1, filename=None, - velocities=None, forces=None, - **kwargs): + format = "MEMORY" + + def __init__( + self, + coordinate_array, + order="fac", + dimensions=None, + dt=1, + filename=None, + velocities=None, + forces=None, + **kwargs, + ): """ Parameters ---------- @@ -317,31 +324,31 @@ def __init__(self, coordinate_array, order='fac', if coordinate_array.ndim == 2 and coordinate_array.shape[1] == 3: coordinate_array = coordinate_array[np.newaxis, :, :] except AttributeError: - errmsg = ("The input has to be a numpy.ndarray that corresponds " - "to the layout specified by the 'order' keyword.") + errmsg = ( + "The input has to be a numpy.ndarray that corresponds " + "to the layout specified by the 'order' keyword." + ) raise TypeError(errmsg) from None self.set_array(coordinate_array, order) - self.n_frames = \ - self.coordinate_array.shape[self.stored_order.find('f')] - self.n_atoms = \ - self.coordinate_array.shape[self.stored_order.find('a')] + self.n_frames = self.coordinate_array.shape[self.stored_order.find("f")] + self.n_atoms = self.coordinate_array.shape[self.stored_order.find("a")] if velocities is not None: try: velocities = np.asarray(velocities, dtype=np.float32) except ValueError: - errmsg = (f"'velocities' must be array-like got " - f"{type(velocities)}") + errmsg = f"'velocities' must be array-like got " f"{type(velocities)}" raise TypeError(errmsg) from None # if single frame, make into array of 1 frame if velocities.ndim == 2: velocities = velocities[np.newaxis, :, :] if not velocities.shape == self.coordinate_array.shape: - raise ValueError('Velocities has wrong shape {} ' - 'to match coordinates {}' - ''.format(velocities.shape, - self.coordinate_array.shape)) + raise ValueError( + "Velocities has wrong shape {} " + "to match coordinates {}" + "".format(velocities.shape, self.coordinate_array.shape) + ) self.velocity_array = velocities.astype(np.float32, copy=False) else: self.velocity_array = None @@ -355,18 +362,17 @@ def __init__(self, coordinate_array, order='fac', if forces.ndim == 2: forces = forces[np.newaxis, :, :] if not forces.shape == self.coordinate_array.shape: - raise ValueError('Forces has wrong shape {} ' - 'to match coordinates {}' - ''.format(forces.shape, - self.coordinate_array.shape)) + raise ValueError( + "Forces has wrong shape {} " + "to match coordinates {}" + "".format(forces.shape, self.coordinate_array.shape) + ) self.force_array = forces.astype(np.float32, copy=False) else: self.force_array = None provided_n_atoms = kwargs.pop("n_atoms", None) - if (provided_n_atoms is not None and - provided_n_atoms != self.n_atoms - ): + if provided_n_atoms is not None and provided_n_atoms != self.n_atoms: raise ValueError( "The provided value for n_atoms ({}) " "does not match the shape of the coordinate " @@ -382,17 +388,18 @@ def __init__(self, coordinate_array, order='fac', try: dimensions = np.asarray(dimensions, dtype=np.float32) except ValueError: - errmsg = (f"'dimensions' must be array-like got " - f"{type(dimensions)}") + errmsg = f"'dimensions' must be array-like got " f"{type(dimensions)}" raise TypeError(errmsg) from None if dimensions.shape == (6,): # single box, tile this to trajectory length # allows modifying the box of some frames dimensions = np.tile(dimensions, (self.n_frames, 1)) elif dimensions.shape != (self.n_frames, 6): - raise ValueError("Provided dimensions array has shape {}. " - "This must be a array of shape (6,) or " - "(n_frames, 6)".format(dimensions.shape)) + raise ValueError( + "Provided dimensions array has shape {}. " + "This must be a array of shape (6,) or " + "(n_frames, 6)".format(dimensions.shape) + ) self.dimensions_array = dimensions self.ts.frame = -1 @@ -408,7 +415,7 @@ def _format_hint(thing): return isinstance(thing, np.ndarray) @staticmethod - def parse_n_atoms(filename, order='fac', **kwargs): + def parse_n_atoms(filename, order="fac", **kwargs): """Deduce number of atoms in a given array of coordinates Parameters @@ -428,14 +435,12 @@ def parse_n_atoms(filename, order='fac', **kwargs): number of atoms in system """ # assume filename is a numpy array - return filename.shape[order.find('a')] + return filename.shape[order.find("a")] def copy(self): """Return a copy of this Memory Reader""" - vels = (self.velocity_array.copy() - if self.velocity_array is not None else None) - fors = (self.force_array.copy() - if self.force_array is not None else None) + vels = self.velocity_array.copy() if self.velocity_array is not None else None + fors = self.force_array.copy() if self.force_array is not None else None dims = self.dimensions_array.copy() new = self.__class__( @@ -446,7 +451,7 @@ def copy(self): forces=fors, dt=self.ts.dt, filename=self.filename, - **self._kwargs + **self._kwargs, ) new[self.ts.frame] @@ -458,7 +463,7 @@ def copy(self): return new - def set_array(self, coordinate_array, order='fac'): + def set_array(self, coordinate_array, order="fac"): """ Set underlying array in desired column order. @@ -474,7 +479,7 @@ def set_array(self, coordinate_array, order='fac'): coordinates). """ # Only make copy if not already in float32 format - self.coordinate_array = coordinate_array.astype('float32', copy=False) + self.coordinate_array = coordinate_array.astype("float32", copy=False) self.stored_format = order def get_array(self): @@ -488,7 +493,9 @@ def _reopen(self): self.ts.frame = -1 self.ts.time = -1 - def timeseries(self, asel=None, atomgroup=None, start=0, stop=-1, step=1, order='afc'): + def timeseries( + self, asel=None, atomgroup=None, start=0, stop=-1, step=1, order="afc" + ): """Return a subset of coordinate data for an AtomGroup in desired column order. If no selection is given, it will return a view of the underlying array, while a copy is returned otherwise. @@ -513,7 +520,7 @@ def timeseries(self, asel=None, atomgroup=None, start=0, stop=-1, step=1, order= .. deprecated:: 2.4.0 Note that `stop` is currently *inclusive* but will be - changed in favour of being *exclusive* in version 3.0. + changed in favour of being *exclusive* in version 3.0. step : int (optional) the number of trajectory frames to skip @@ -535,16 +542,19 @@ def timeseries(self, asel=None, atomgroup=None, start=0, stop=-1, step=1, order= warnings.warn( "asel argument to timeseries will be renamed to" "'atomgroup' in 3.0, see #3911", - category=DeprecationWarning) + category=DeprecationWarning, + ) if atomgroup: raise ValueError("Cannot provide both asel and atomgroup kwargs") atomgroup = asel - if stop != -1: - warnings.warn("MemoryReader.timeseries inclusive `stop` " - "indexing will be removed in 3.0 in favour of exclusive " - "indexing", category=DeprecationWarning) + warnings.warn( + "MemoryReader.timeseries inclusive `stop` " + "indexing will be removed in 3.0 in favour of exclusive " + "indexing", + category=DeprecationWarning, + ) array = self.get_array() if order == self.stored_order: @@ -562,40 +572,41 @@ def timeseries(self, asel=None, atomgroup=None, start=0, stop=-1, step=1, order= array = np.swapaxes(array, 2, 0) array = np.swapaxes(array, 1, 2) - a_index = order.find('a') - f_index = order.find('f') - stop_index = stop+1 + a_index = order.find("a") + f_index = order.find("f") + stop_index = stop + 1 if stop_index == 0: stop_index = None - basic_slice = ([slice(None)] * f_index + - [slice(start, stop_index, step)] + - [slice(None)] * (2-f_index)) + basic_slice = ( + [slice(None)] * f_index + + [slice(start, stop_index, step)] + + [slice(None)] * (2 - f_index) + ) # Return a view if either: # 1) atomgroup is None # 2) atomgroup corresponds to the selection of all atoms. array = array[tuple(basic_slice)] - if (atomgroup is None or atomgroup is atomgroup.universe.atoms): + if atomgroup is None or atomgroup is atomgroup.universe.atoms: return array else: if len(atomgroup) == 0: - raise ValueError("Timeseries requires at least one atom " - "to analyze") + raise ValueError("Timeseries requires at least one atom " "to analyze") # If selection is specified, return a copy return array.take(asel.indices, a_index) def _read_next_timestep(self, ts=None): """copy next frame into timestep""" - if self.ts.frame >= self.n_frames-1: - raise IOError(errno.EIO, 'trying to go over trajectory limit') + if self.ts.frame >= self.n_frames - 1: + raise IOError(errno.EIO, "trying to go over trajectory limit") if ts is None: ts = self.ts ts.frame += 1 - f_index = self.stored_order.find('f') - basic_slice = ([slice(None)]*(f_index) + - [self.ts.frame] + - [slice(None)]*(2-f_index)) + f_index = self.stored_order.find("f") + basic_slice = ( + [slice(None)] * (f_index) + [self.ts.frame] + [slice(None)] * (2 - f_index) + ) _replace_positions_array(ts, self.coordinate_array[tuple(basic_slice)]) _replace_dimensions(ts, self.dimensions_array[self.ts.frame]) if self.velocity_array is not None: @@ -614,15 +625,12 @@ def _read_frame(self, i): def __repr__(self): """String representation""" - return ("<{cls} with {nframes} frames of {natoms} atoms>" - "".format( - cls=self.__class__.__name__, - nframes=self.n_frames, - natoms=self.n_atoms - )) + return "<{cls} with {nframes} frames of {natoms} atoms>" "".format( + cls=self.__class__.__name__, nframes=self.n_frames, natoms=self.n_atoms + ) def add_transformations(self, *transformations): - """ Add all transformations to be applied to the trajectory. + """Add all transformations to be applied to the trajectory. This function take as list of transformations as an argument. These transformations are functions that will be called by the Reader and given @@ -648,10 +656,10 @@ def add_transformations(self, *transformations): -------- :mod:`MDAnalysis.transformations` """ - #Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` - #to avoid unintended behaviour where the coordinates of each frame are transformed - #multiple times when iterating over the trajectory. - #In this method, the trajectory is modified all at once and once only. + # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` + # to avoid unintended behaviour where the coordinates of each frame are transformed + # multiple times when iterating over the trajectory. + # In this method, the trajectory is modified all at once and once only. super(MemoryReader, self).add_transformations(*transformations) for i, ts in enumerate(self): @@ -659,7 +667,7 @@ def add_transformations(self, *transformations): ts = transform(ts) def _apply_transformations(self, ts): - """ Applies the transformations to the timestep.""" + """Applies the transformations to the timestep.""" # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` # to avoid applying the same transformations multiple times on each frame diff --git a/package/MDAnalysis/core/_get_readers.py b/package/MDAnalysis/core/_get_readers.py index 45d61b3cad..926c2e37a6 100644 --- a/package/MDAnalysis/core/_get_readers.py +++ b/package/MDAnalysis/core/_get_readers.py @@ -192,12 +192,8 @@ def get_writer_for(filename, format=None, multiframe=None): format = format.upper() if multiframe is None: # Multiframe takes priority, else use singleframe - options = copy.copy( - _SINGLEFRAME_WRITERS - ) # do copy to avoid changing in place - options.update( - _MULTIFRAME_WRITERS - ) # update overwrites existing entries + options = copy.copy(_SINGLEFRAME_WRITERS) # do copy to avoid changing in place + options.update(_MULTIFRAME_WRITERS) # update overwrites existing entries errmsg = "No trajectory or frame writer for format '{0}'" elif multiframe is True: options = _MULTIFRAME_WRITERS diff --git a/package/MDAnalysis/core/groups.py b/package/MDAnalysis/core/groups.py index 40044be7c8..54e5a9a886 100644 --- a/package/MDAnalysis/core/groups.py +++ b/package/MDAnalysis/core/groups.py @@ -160,9 +160,7 @@ def make_classes(): for cls in groups: bases[cls] = GBase._subclass(is_group=True) # CBase for patching all components - CBase = bases[ComponentBase] = _TopologyAttrContainer._subclass( - is_group=False - ) + CBase = bases[ComponentBase] = _TopologyAttrContainer._subclass(is_group=False) for cls in components: bases[cls] = CBase._subclass(is_group=False) @@ -420,14 +418,9 @@ def __getattr__(self, attr): ) # missing required topologyattr else: - err = ( - "{selfcls}.{attrname} not available; " - "this requires {topattr}" - ) + err = "{selfcls}.{attrname} not available; " "this requires {topattr}" raise NoDataError( - err.format( - selfcls=selfcls, attrname=attrname, topattr=topattr - ) + err.format(selfcls=selfcls, attrname=attrname, topattr=topattr) ) else: @@ -534,9 +527,7 @@ def wrapped(self, other): "".format(function.__name__) ) if self.universe is not other.universe: - raise ValueError( - "Can't operate on objects from different Universes" - ) + raise ValueError("Can't operate on objects from different Universes") return function(self, other) return wrapped @@ -673,10 +664,7 @@ def __getattr__(self, attr): if attr in _TOPOLOGY_ATTRS: cls = _TOPOLOGY_ATTRS[attr] if attr == cls.singular and attr != cls.attrname: - err = ( - "{selfcls} has no attribute {attr}. " - "Do you mean {plural}?" - ) + err = "{selfcls} has no attribute {attr}. " "Do you mean {plural}?" raise AttributeError( err.format(selfcls=selfcls, attr=attr, plural=cls.attrname) ) @@ -740,9 +728,7 @@ def __radd__(self, other): else: raise TypeError( "unsupported operand type(s) for +:" - " '{}' and '{}'".format( - type(self).__name__, type(other).__name__ - ) + " '{}' and '{}'".format(type(self).__name__, type(other).__name__) ) def __sub__(self, other): @@ -895,9 +881,7 @@ def _asunique(self, group, sorted=False, set_mask=False): if sorted: if set_mask: - unique_ix, restore_mask = np.unique( - self.ix, return_inverse=True - ) + unique_ix, restore_mask = np.unique(self.ix, return_inverse=True) self._unique_restore_mask = restore_mask else: unique_ix = unique_int_1d(self.ix) @@ -1173,9 +1157,7 @@ def center(self, weights, wrap=False, unwrap=False, compound="group"): if wrap: coords = atoms.pack_into_box(inplace=False) elif unwrap: - coords = atoms.unwrap( - compound=comp, reference=None, inplace=False - ) + coords = atoms.unwrap(compound=comp, reference=None, inplace=False) else: coords = atoms.positions # If there's no atom, return its (empty) coordinates unchanged. @@ -1187,16 +1169,14 @@ def center(self, weights, wrap=False, unwrap=False, compound="group"): return coords.mean(axis=0) # promote weights to dtype if required: weights = weights.astype(dtype, copy=False) - return ( - np.einsum("ij,ij->j", coords, weights[:, None]) / weights.sum() - ) + return np.einsum("ij,ij->j", coords, weights[:, None]) / weights.sum() # When compound split caching gets implemented it will be clever to # preempt at this point whether or not stable sorting will be needed # later for unwrap (so that we don't split now with non-stable sort, # only to have to re-split with stable sort if unwrap is requested). - (atom_masks, compound_masks, n_compounds) = ( - self._split_by_compound_indices(comp) + (atom_masks, compound_masks, n_compounds) = self._split_by_compound_indices( + comp ) # Unwrap Atoms @@ -1218,9 +1198,7 @@ def center(self, weights, wrap=False, unwrap=False, compound="group"): _centers = _coords.mean(axis=1) else: _weights = weights[atom_mask] - _centers = np.einsum( - "ijk,ijk->ik", _coords, _weights[:, :, None] - ) + _centers = np.einsum("ijk,ijk->ik", _coords, _weights[:, :, None]) _centers /= _weights.sum(axis=1)[:, None] centers[compound_mask] = _centers if wrap: @@ -1406,8 +1384,8 @@ def accumulate(self, attribute, function=np.sum, compound="group"): if comp == "group": return function(attribute_values, axis=0) - (atom_masks, compound_masks, n_compounds) = ( - self._split_by_compound_indices(comp) + (atom_masks, compound_masks, n_compounds) = self._split_by_compound_indices( + comp ) higher_dims = list(attribute_values.shape[1:]) @@ -2010,8 +1988,7 @@ def unwrap(self, compound="fragments", reference="com", inplace=True): # ResidueGroups or SegmentGroups if reference == "com" and not hasattr(unique_atoms, "masses"): raise NoDataError( - "Cannot perform unwrap with reference='com', " - "this requires masses." + "Cannot perform unwrap with reference='com', " "this requires masses." ) # Sanity checking of the compound parameter is done downstream in @@ -2079,9 +2056,7 @@ def unwrap(self, compound="fragments", reference="com", inplace=True): refpos = positions[atom_mask].mean(axis=1) refpos = refpos.astype(np.float32, copy=False) target = distances.apply_PBC(refpos, self.dimensions) - positions[atom_mask] += ( - target[:, None, :] - refpos[:, None, :] - ) + positions[atom_mask] += target[:, None, :] - refpos[:, None, :] if inplace: unique_atoms.positions = positions if not atoms.isunique: @@ -2241,9 +2216,7 @@ def concatenate(self, other): .. versionadded:: 0.16.0 """ o_ix = other.ix_array - return self._derived_class( - np.concatenate([self.ix, o_ix]), self.universe - ) + return self._derived_class(np.concatenate([self.ix, o_ix]), self.universe) @_only_same_level def union(self, other): @@ -2330,9 +2303,7 @@ def intersection(self, other): .. versionadded:: 0.16 """ o_ix = other.ix_array - return self._derived_class( - np.intersect1d(self.ix, o_ix), self.universe - ) + return self._derived_class(np.intersect1d(self.ix, o_ix), self.universe) @_only_same_level def subtract(self, other): @@ -2836,9 +2807,7 @@ def residues(self, new): errmsg = ( "Can only set AtomGroup residues to Residue " "or ResidueGroup not {}".format( - ", ".join( - type(r) for r in new if not isinstance(r, Residue) - ) + ", ".join(type(r) for r in new if not isinstance(r, Residue)) ) ) raise TypeError(errmsg) from None @@ -2880,8 +2849,7 @@ def segments(self): @segments.setter def segments(self, new): raise NotImplementedError( - "Cannot assign Segments to AtomGroup. " - "Segments are assigned to Residues" + "Cannot assign Segments to AtomGroup. " "Segments are assigned to Residues" ) @property @@ -3010,9 +2978,7 @@ def asunique(self, sorted=False): .. versionadded:: 2.0.0 """ - return self._asunique( - sorted=sorted, group=self.universe.atoms, set_mask=True - ) + return self._asunique(sorted=sorted, group=self.universe.atoms, set_mask=True) @property def positions(self): @@ -3612,10 +3578,7 @@ def split(self, level): ) raise ValueError(errmsg) from None - return [ - self[levelindices == index] - for index in unique_int_1d(levelindices) - ] + return [self[levelindices == index] for index in unique_int_1d(levelindices)] def guess_bonds(self, vdwradii=None, fudge_factor=0.55, lower_bound=0.1): """Guess bonds, angles, and dihedrals between the atoms in this @@ -3696,9 +3659,7 @@ def bond(self): .. versionadded:: 0.11.0 """ if len(self) != 2: - raise ValueError( - "bond only makes sense for a group with exactly 2 atoms" - ) + raise ValueError("bond only makes sense for a group with exactly 2 atoms") return topologyobjects.Bond(self.ix, self.universe) @property @@ -3715,9 +3676,7 @@ def angle(self): .. versionadded:: 0.11.0 """ if len(self) != 3: - raise ValueError( - "angle only makes sense for a group with exactly 3 atoms" - ) + raise ValueError("angle only makes sense for a group with exactly 3 atoms") return topologyobjects.Angle(self.ix, self.universe) @property @@ -3791,9 +3750,7 @@ def cmap(self): .. versionadded:: 1.0.0 """ if len(self) != 5: - raise ValueError( - "cmap only makes sense for a group with exactly 5 atoms" - ) + raise ValueError("cmap only makes sense for a group with exactly 5 atoms") return topologyobjects.CMap(self.ix, self.universe) convert_to = Accessor("convert_to", ConverterWrapper) @@ -3914,9 +3871,7 @@ def write( # Try and select a Class using get_ methods (becomes `writer`) # Once (and if!) class is selected, use it in with block try: - writer = get_writer_for( - filename, format=file_format, multiframe=multiframe - ) + writer = get_writer_for(filename, format=file_format, multiframe=multiframe) except (ValueError, TypeError): pass else: @@ -4129,9 +4084,7 @@ def segments(self, new): errmsg = ( "Can only set ResidueGroup segments to Segment " "or SegmentGroup, not {}".format( - ", ".join( - type(r) for r in new if not isinstance(r, Segment) - ) + ", ".join(type(r) for r in new if not isinstance(r, Segment)) ) ) raise TypeError(errmsg) from None @@ -4450,9 +4403,7 @@ class ComponentBase(_MutableBase): def __init__(self, ix, u): # index of component if not isinstance(ix, numbers.Integral): - raise IndexError( - "Component can only be indexed by a single integer" - ) + raise IndexError("Component can only be indexed by a single integer") self._ix = ix self._u = u @@ -4462,14 +4413,9 @@ def __getattr__(self, attr): if attr in _TOPOLOGY_ATTRS: cls = _TOPOLOGY_ATTRS[attr] if attr == cls.attrname and attr != cls.singular: - err = ( - "{selfcls} has no attribute {attr}. " - "Do you mean {singular}?" - ) + err = "{selfcls} has no attribute {attr}. " "Do you mean {singular}?" raise AttributeError( - err.format( - selfcls=selfcls, attr=attr, singular=cls.singular - ) + err.format(selfcls=selfcls, attr=attr, singular=cls.singular) ) else: err = "This Universe does not contain {singular} information" @@ -4510,9 +4456,7 @@ def __add__(self, other): """ o_ix = other.ix_array - return self.level.plural( - np.concatenate([self.ix_array, o_ix]), self.universe - ) + return self.level.plural(np.concatenate([self.ix_array, o_ix]), self.universe) def __radd__(self, other): """Using built-in sum requires supporting 0 + self. If other is @@ -4533,9 +4477,7 @@ def __radd__(self, other): else: raise TypeError( "unsupported operand type(s) for +:" - " '{}' and '{}'".format( - type(self).__name__, type(other).__name__ - ) + " '{}' and '{}'".format(type(self).__name__, type(other).__name__) ) @property @@ -4612,8 +4554,7 @@ def residue(self): def residue(self, new): if not isinstance(new, Residue): raise TypeError( - "Can only set Atom residue to Residue, not {}" - "".format(type(new)) + "Can only set Atom residue to Residue, not {}" "".format(type(new)) ) self.universe._topology.tt.move_atom(self.ix, new.resindex) @@ -4744,8 +4685,7 @@ def segment(self): def segment(self, new): if not isinstance(new, Segment): raise TypeError( - "Can only set Residue segment to Segment, not {}" - "".format(type(new)) + "Can only set Residue segment to Segment, not {}" "".format(type(new)) ) self.universe._topology.tt.move_residue(self.ix, new.segindex) @@ -4794,9 +4734,7 @@ def residues(self): """A :class:`ResidueGroup` of :class:`Residues` present in this :class:`Segment`. """ - rg = self.universe.residues[ - self.universe._topology.resindices[self][0] - ] + rg = self.universe.residues[self.universe._topology.resindices[self][0]] rg._cache["isunique"] = True rg._cache["issorted"] = True rg._cache["sorted_unique"] = rg diff --git a/package/MDAnalysis/core/selection.py b/package/MDAnalysis/core/selection.py index d47f4d7ac1..01dbb79bf0 100644 --- a/package/MDAnalysis/core/selection.py +++ b/package/MDAnalysis/core/selection.py @@ -64,6 +64,7 @@ #: Delimiters include ":", "-", "to" and can have arbitrary whitespace. RANGE_PATTERN = r"\s*(?:[:-]| to )\s*" + def is_keyword(val): """Is val a selection keyword? @@ -73,10 +74,9 @@ def is_keyword(val): - (Parentheses) - The value `None` (used as EOF in selection strings) """ - return (val in _SELECTIONDICT or - val in _OPERATIONS or - val in ['(', ')'] or - val is None) + return ( + val in _SELECTIONDICT or val in _OPERATIONS or val in ["(", ")"] or val is None + ) def grab_not_keywords(tokens): @@ -145,18 +145,22 @@ def join_separated_values(values): except IndexError: given = f"{' '.join(_values)} {v} {' '.join(values)}" raise SelectionError(f"Invalid expression given: {given}") - elif _values and (v[:2] in ('--', 'to') or v[0] == ":" or - any(_values[-1].endswith(x) for x in DELIMITERS)): + elif _values and ( + v[:2] in ("--", "to") + or v[0] == ":" + or any(_values[-1].endswith(x) for x in DELIMITERS) + ): _values[-1] = f"{_values[-1]} {v}" else: _values.append(v) return _values + _SELECTIONDICT = {} _OPERATIONS = {} # These are named args to select_atoms that have a special meaning and must # not be allowed as names for the 'group' keyword. -_RESERVED_KWARGS=('updating',) +_RESERVED_KWARGS = ("updating",) # And and Or are exception and aren't strictly a Selection @@ -166,7 +170,7 @@ class _Operationmeta(type): def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - _OPERATIONS[classdict['token']] = cls + _OPERATIONS[classdict["token"]] = cls except KeyError: pass @@ -182,7 +186,7 @@ def apply(self, *args, **kwargs): class AndOperation(LogicOperation): - token = 'and' + token = "and" precedence = 3 def _apply(self, group): @@ -196,7 +200,7 @@ def _apply(self, group): class OrOperation(LogicOperation): - token = 'or' + token = "or" precedence = 3 def _apply(self, group): @@ -209,16 +213,19 @@ def _apply(self, group): return group.universe.atoms[idx] + def return_empty_on_apply(func): """ Decorator to return empty AtomGroups from the apply() function without evaluating it """ + @functools.wraps(func) def _apply(self, group): if len(group) == 0: return group return func(self, group) + return _apply @@ -226,8 +233,8 @@ class _Selectionmeta(type): def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - _SELECTIONDICT[classdict['token']] = cls - _SELECTIONDICT[classdict['token'].lower()] = cls + _SELECTIONDICT[classdict["token"]] = cls + _SELECTIONDICT[classdict["token"].lower()] = cls except KeyError: pass @@ -242,7 +249,7 @@ def apply(self, *args, **kwargs): class AllSelection(Selection): - token = 'all' + token = "all" def _apply(self, group): # Check whether group is identical to the one stored @@ -262,7 +269,7 @@ def __init__(self, parser, tokens): class NotSelection(UnarySelection): - token = 'not' + token = "not" precedence = 5 def _apply(self, group): @@ -271,7 +278,7 @@ def _apply(self, group): class GlobalSelection(UnarySelection): - token = 'global' + token = "global" precedence = 5 def _apply(self, group): @@ -286,7 +293,7 @@ class ByResSelection(UnarySelection): Use :code:`"resindices"` instead of :code:`"resids"` (see #2669 and #2672) """ - token = 'byres' + token = "byres" precedence = 1 def _apply(self, group): @@ -298,7 +305,7 @@ def _apply(self, group): class AroundSelection(Selection): - token = 'around' + token = "around" precedence = 1 def __init__(self, parser, tokens): @@ -318,16 +325,17 @@ def _apply(self, group): return sys[[]] box = group.dimensions if self.periodic else None - pairs = distances.capped_distance(sel.positions, sys.positions, - self.cutoff, box=box, - return_distances=False) + pairs = distances.capped_distance( + sel.positions, sys.positions, self.cutoff, box=box, return_distances=False + ) if pairs.size > 0: indices = np.sort(pairs[:, 1]) return sys[np.asarray(indices, dtype=np.int64)] + class SphericalLayerSelection(Selection): - token = 'sphlayer' + token = "sphlayer" precedence = 1 def __init__(self, parser, tokens): @@ -346,10 +354,14 @@ def _apply(self, group): box = group.dimensions if self.periodic else None ref = sel.center_of_geometry().reshape(1, 3).astype(np.float32) - pairs = distances.capped_distance(ref, group.positions, self.exRadius, - min_cutoff=self.inRadius, - box=box, - return_distances=False) + pairs = distances.capped_distance( + ref, + group.positions, + self.exRadius, + min_cutoff=self.inRadius, + box=box, + return_distances=False, + ) if pairs.size > 0: indices = np.sort(pairs[:, 1]) @@ -357,7 +369,7 @@ def _apply(self, group): class IsoLayerSelection(Selection): - token = 'isolayer' + token = "isolayer" precedence = 1 def __init__(self, parser, tokens): @@ -378,17 +390,17 @@ def _apply(self, group): return sys[[]] box = group.dimensions if self.periodic else None - pairs_outer = distances.capped_distance(sel.positions, sys.positions, - self.exRadius, box=box, - return_distances=False) - pairs_inner = distances.capped_distance(sel.positions, sys.positions, - self.inRadius, box=box, - return_distances=False) + pairs_outer = distances.capped_distance( + sel.positions, sys.positions, self.exRadius, box=box, return_distances=False + ) + pairs_inner = distances.capped_distance( + sel.positions, sys.positions, self.inRadius, box=box, return_distances=False + ) if pairs_outer.size > 0: - sys_ind_outer = np.sort(np.unique(pairs_outer[:,1])) + sys_ind_outer = np.sort(np.unique(pairs_outer[:, 1])) if pairs_inner.size > 0: - sys_ind_inner = np.sort(np.unique(pairs_inner[:,1])) + sys_ind_inner = np.sort(np.unique(pairs_inner[:, 1])) indices = sys_ind_outer[~np.isin(sys_ind_outer, sys_ind_inner)] else: indices = sys_ind_outer @@ -397,7 +409,7 @@ def _apply(self, group): class SphericalZoneSelection(Selection): - token = 'sphzone' + token = "sphzone" precedence = 1 def __init__(self, parser, tokens): @@ -415,9 +427,9 @@ def _apply(self, group): box = group.dimensions if self.periodic else None ref = sel.center_of_geometry().reshape(1, 3).astype(np.float32) - pairs = distances.capped_distance(ref, group.positions, self.cutoff, - box=box, - return_distances=False) + pairs = distances.capped_distance( + ref, group.positions, self.cutoff, box=box, return_distances=False + ) if pairs.size > 0: indices = np.sort(pairs[:, 1]) @@ -442,21 +454,24 @@ def _apply(self, group): "The diameter of the cylinder selection ({:.3f}) is larger " "than the unit cell's x dimension ({:.3f}). Can only do " "selections where it is smaller or equal." - "".format(2*self.exRadius, box[0])) + "".format(2 * self.exRadius, box[0]) + ) if 2 * self.exRadius > box[1]: raise NotImplementedError( "The diameter of the cylinder selection ({:.3f}) is larger " "than the unit cell's y dimension ({:.3f}). Can only do " "selections where it is smaller or equal." - "".format(2*self.exRadius, box[1])) + "".format(2 * self.exRadius, box[1]) + ) if cyl_z_hheight > box[2]: raise NotImplementedError( "The total length of the cylinder selection in z ({:.3f}) " "is larger than the unit cell's z dimension ({:.3f}). Can " "only do selections where it is smaller or equal." - "".format(cyl_z_hheight, box[2])) + "".format(cyl_z_hheight, box[2]) + ) - if np.all(group.dimensions[3:] == 90.): + if np.all(group.dimensions[3:] == 90.0): # Orthogonal version vecs -= box[:3] * np.rint(vecs / box[:3]) else: @@ -473,7 +488,7 @@ def _apply(self, group): group = group[mask] # Radial vectors from sel to each in group - radii = vecs[:, 0]**2 + vecs[:, 1]**2 + radii = vecs[:, 0] ** 2 + vecs[:, 1] ** 2 mask = radii < self.exRadius**2 try: mask &= radii > self.inRadius**2 @@ -485,7 +500,7 @@ def _apply(self, group): class CylindricalZoneSelection(CylindricalSelection): - token = 'cyzone' + token = "cyzone" precedence = 1 def __init__(self, parser, tokens): @@ -498,7 +513,7 @@ def __init__(self, parser, tokens): class CylindricalLayerSelection(CylindricalSelection): - token = 'cylayer' + token = "cylayer" precedence = 1 def __init__(self, parser, tokens): @@ -512,7 +527,7 @@ def __init__(self, parser, tokens): class PointSelection(Selection): - token = 'point' + token = "point" def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -528,9 +543,13 @@ def _apply(self, group): indices = [] box = group.dimensions if self.periodic else None - pairs = distances.capped_distance(self.ref[None, :], group.positions, self.cutoff, - box=box, - return_distances=False) + pairs = distances.capped_distance( + self.ref[None, :], + group.positions, + self.cutoff, + box=box, + return_distances=False, + ) if pairs.size > 0: indices = np.sort(pairs[:, 1]) @@ -538,7 +557,7 @@ def _apply(self, group): class AtomSelection(Selection): - token = 'atom' + token = "atom" def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -556,7 +575,7 @@ def _apply(self, group): class BondedSelection(Selection): - token = 'bonded' + token = "bonded" precedence = 1 def __init__(self, parser, tokens): @@ -587,15 +606,16 @@ def _apply(self, group): class SelgroupSelection(Selection): - token = 'group' + token = "group" def __init__(self, parser, tokens): super().__init__(parser, tokens) grpname = tokens.popleft() if grpname in _RESERVED_KWARGS: - raise TypeError("The '{}' keyword is reserved and cannot be " - "used as a selection group name." - .format(grpname)) + raise TypeError( + "The '{}' keyword is reserved and cannot be " + "used as a selection group name.".format(grpname) + ) try: self.grp = parser.selgroups[grpname] except KeyError: @@ -612,6 +632,7 @@ class SingleCharSelection(Selection): .. versionadded:: 2.1.0 """ + def __init__(self, parser, tokens): super().__init__(parser, tokens) vals = grab_not_keywords(tokens) @@ -635,6 +656,7 @@ class _ProtoStringSelection(Selection): .. versionchanged:: 1.0.0 Supports multiple wildcards, based on fnmatch """ + def __init__(self, parser, tokens): super().__init__(parser, tokens) vals = grab_not_keywords(tokens) @@ -665,8 +687,9 @@ class AromaticSelection(Selection): Aromaticity is available in the `aromaticities` attribute and is made available through RDKit""" - token = 'aromatic' - field = 'aromaticities' + + token = "aromatic" + field = "aromaticities" def _apply(self, group): return group[group.aromaticities] @@ -687,7 +710,8 @@ class SmartsSelection(Selection): limit cases where too few matches were generated. A warning is now also thrown if ``maxMatches`` has been reached. """ - token = 'smarts' + + token = "smarts" def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -720,10 +744,12 @@ def _apply(self, group): try: from rdkit import Chem except ImportError: - raise ImportError("RDKit is required for SMARTS-based atom " - "selection but it's not installed. Try " - "installing it with \n" - "conda install -c conda-forge rdkit") + raise ImportError( + "RDKit is required for SMARTS-based atom " + "selection but it's not installed. Try " + "installing it with \n" + "conda install -c conda-forge rdkit" + ) pattern = Chem.MolFromSmarts(self.pattern) if not pattern: raise ValueError(f"{self.pattern!r} is not a valid SMARTS query") @@ -732,14 +758,16 @@ def _apply(self, group): self.smarts_kwargs.setdefault("maxMatches", max(1000, len(group) * 10)) matches = mol.GetSubstructMatches(pattern, **self.smarts_kwargs) if len(matches) == self.smarts_kwargs["maxMatches"]: - warnings.warn("Your smarts-based atom selection returned the max" - "number of matches. This indicates that not all" - "matching atoms were selected. When calling" - "atom_group.select_atoms(), the default value" - "of maxMatches is max(100, len(atom_group * 10)). " - "To fix this, add the following argument to " - "select_atoms: \n" - "smarts_kwargs={maxMatches: }") + warnings.warn( + "Your smarts-based atom selection returned the max" + "number of matches. This indicates that not all" + "matching atoms were selected. When calling" + "atom_group.select_atoms(), the default value" + "of maxMatches is max(100, len(atom_group * 10)). " + "To fix this, add the following argument to " + "select_atoms: \n" + "smarts_kwargs={maxMatches: }" + ) # flatten all matches and remove duplicated indices indices = np.unique([idx for match in matches for idx in match]) # create boolean mask for atoms based on index @@ -755,7 +783,8 @@ class ResidSelection(Selection): resid 1:10 """ - token = 'resid' + + token = "resid" def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -802,10 +831,11 @@ def _apply(self, group): except (AttributeError, NoDataError): icodes = None # if no icodes and icodes are part of selection, cause a fuss - if (any(v[1] for v in self.uppers) or - any(v[1] for v in self.lowers)): - errmsg = ("Selection specified icodes, while the topology " - "doesn't have any.") + if any(v[1] for v in self.uppers) or any(v[1] for v in self.lowers): + errmsg = ( + "Selection specified icodes, while the topology " + "doesn't have any." + ) raise ValueError(errmsg) from None if not icodes is None: @@ -892,9 +922,11 @@ def __init__(self, parser, tokens): elif lower == "true": bval = True else: - raise ValueError(f"'{val}' is an invalid value " - "for boolean selection. " - "Use 'True' or 'False'") + raise ValueError( + f"'{val}' is an invalid value " + "for boolean selection. " + "Use 'True' or 'False'" + ) self.values.append(bval) def _apply(self, group): @@ -976,26 +1008,27 @@ def _apply(self, group): else: low, high = lower - 1, lower + 1 fp = "https://docs.python.org/3.8/tutorial/floatingpoint.html" - msg = ("Using float equality to select atoms is " - "not recommended because of inherent " - "limitations in representing numbers on " - f"computers (see {fp} for more). " - "Instead, we recommend using a range " - f"to select, e.g. '{self.token} {low} to {high}'. " - "If you still want to compare floats, use the " - "`atol` and `rtol` keywords to modify the tolerance " - "for `np.isclose`.") + msg = ( + "Using float equality to select atoms is " + "not recommended because of inherent " + "limitations in representing numbers on " + f"computers (see {fp} for more). " + "Instead, we recommend using a range " + f"to select, e.g. '{self.token} {low} to {high}'. " + "If you still want to compare floats, use the " + "`atol` and `rtol` keywords to modify the tolerance " + "for `np.isclose`." + ) warnings.warn(msg, category=SelectionWarning) - thismask = np.isclose(vals, lower, atol=self.atol, - rtol=self.rtol) + thismask = np.isclose(vals, lower, atol=self.atol, rtol=self.rtol) mask |= thismask return group[mask] class ByNumSelection(RangeSelection): - token = 'bynum' - field = 'indices' + token = "bynum" + field = "indices" value_offset = 1 # queries are in 1 based indices @@ -1018,38 +1051,129 @@ class ProteinSelection(Selection): prot_res changed to set (from numpy array) performance improved by ~100x on larger systems """ - token = 'protein' + + token = "protein" prot_res = { # CHARMM top_all27_prot_lipid.rtf - 'ALA', 'ARG', 'ASN', 'ASP', 'CYS', 'GLN', 'GLU', 'GLY', 'HSD', - 'HSE', 'HSP', 'ILE', 'LEU', 'LYS', 'MET', 'PHE', 'PRO', 'SER', 'THR', - 'TRP', 'TYR', 'VAL', 'ALAD', + "ALA", + "ARG", + "ASN", + "ASP", + "CYS", + "GLN", + "GLU", + "GLY", + "HSD", + "HSE", + "HSP", + "ILE", + "LEU", + "LYS", + "MET", + "PHE", + "PRO", + "SER", + "THR", + "TRP", + "TYR", + "VAL", + "ALAD", ## 'CHO','EAM', # -- special formyl and ethanolamine termini of gramicidin # PDB - 'HIS', 'MSE', + "HIS", + "MSE", # from Gromacs 4.5.3 oplsaa.ff/aminoacids.rtp - 'ARGN', 'ASPH', 'CYS2', 'CYSH', 'QLN', 'PGLU', 'GLUH', 'HIS1', 'HISD', - 'HISE', 'HISH', 'LYSH', + "ARGN", + "ASPH", + "CYS2", + "CYSH", + "QLN", + "PGLU", + "GLUH", + "HIS1", + "HISD", + "HISE", + "HISH", + "LYSH", # from Gromacs 4.5.3 gromos53a6.ff/aminoacids.rtp - 'ASN1', 'CYS1', 'HISA', 'HISB', 'HIS2', + "ASN1", + "CYS1", + "HISA", + "HISB", + "HIS2", # from Gromacs 4.5.3 amber03.ff/aminoacids.rtp - 'HID', 'HIE', 'HIP', 'ORN', 'DAB', 'LYN', 'HYP', 'CYM', 'CYX', 'ASH', - 'GLH', 'ACE', 'NME', + "HID", + "HIE", + "HIP", + "ORN", + "DAB", + "LYN", + "HYP", + "CYM", + "CYX", + "ASH", + "GLH", + "ACE", + "NME", # from Gromacs 2016.3 amber99sb-star-ildn.ff/aminoacids.rtp - 'NALA', 'NGLY', 'NSER', 'NTHR', 'NLEU', 'NILE', 'NVAL', 'NASN', 'NGLN', - 'NARG', 'NHID', 'NHIE', 'NHIP', 'NTRP', 'NPHE', 'NTYR', 'NGLU', 'NASP', - 'NLYS', 'NPRO', 'NCYS', 'NCYX', 'NMET', 'CALA', 'CGLY', 'CSER', 'CTHR', - 'CLEU', 'CILE', 'CVAL', 'CASF', 'CASN', 'CGLN', 'CARG', 'CHID', 'CHIE', - 'CHIP', 'CTRP', 'CPHE', 'CTYR', 'CGLU', 'CASP', 'CLYS', 'CPRO', 'CCYS', - 'CCYX', 'CMET', 'CME', 'ASF', + "NALA", + "NGLY", + "NSER", + "NTHR", + "NLEU", + "NILE", + "NVAL", + "NASN", + "NGLN", + "NARG", + "NHID", + "NHIE", + "NHIP", + "NTRP", + "NPHE", + "NTYR", + "NGLU", + "NASP", + "NLYS", + "NPRO", + "NCYS", + "NCYX", + "NMET", + "CALA", + "CGLY", + "CSER", + "CTHR", + "CLEU", + "CILE", + "CVAL", + "CASF", + "CASN", + "CGLN", + "CARG", + "CHID", + "CHIE", + "CHIP", + "CTRP", + "CPHE", + "CTYR", + "CGLU", + "CASP", + "CLYS", + "CPRO", + "CCYS", + "CCYX", + "CMET", + "CME", + "ASF", } def _apply(self, group): resname_attr = group.universe._topology.resnames # which values in resname attr are in prot_res? - matches = [ix for (nm, ix) in resname_attr.namedict.items() - if nm in self.prot_res] + matches = [ + ix for (nm, ix) in resname_attr.namedict.items() if nm in self.prot_res + ] # index of each atom's resname nmidx = resname_attr.nmidx[group.resindices] # intersect atom's resname index and matches to prot_res @@ -1072,23 +1196,51 @@ class NucleicSelection(Selection): nucl_res changed to set (from numpy array) performance improved by ~100x on larger systems """ - token = 'nucleic' + + token = "nucleic" nucl_res = { - 'ADE', 'URA', 'CYT', 'GUA', 'THY', 'DA', 'DC', 'DG', 'DT', 'RA', - 'RU', 'RG', 'RC', 'A', 'T', 'U', 'C', 'G', - 'DA5', 'DC5', 'DG5', 'DT5', - 'DA3', 'DC3', 'DG3', 'DT3', - 'RA5', 'RU5', 'RG5', 'RC5', - 'RA3', 'RU3', 'RG3', 'RC3' + "ADE", + "URA", + "CYT", + "GUA", + "THY", + "DA", + "DC", + "DG", + "DT", + "RA", + "RU", + "RG", + "RC", + "A", + "T", + "U", + "C", + "G", + "DA5", + "DC5", + "DG5", + "DT5", + "DA3", + "DC3", + "DG3", + "DT3", + "RA5", + "RU5", + "RG5", + "RC5", + "RA3", + "RU3", + "RG3", + "RC3", } def _apply(self, group): resnames = group.universe._topology.resnames nmidx = resnames.nmidx[group.resindices] - matches = [ix for (nm, ix) in resnames.namedict.items() - if nm in self.nucl_res] + matches = [ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res] mask = np.isin(nmidx, matches) return group[mask] @@ -1131,11 +1283,7 @@ def _apply(self, group): resnames = group.universe._topology.resnames nmidx = resnames.nmidx[group.resindices] - matches = [ - ix - for (nm, ix) in resnames.namedict.items() - if nm in self.water_res - ] + matches = [ix for (nm, ix) in resnames.namedict.items() if nm in self.water_res] mask = np.isin(nmidx, matches) return group[mask] @@ -1152,22 +1300,25 @@ class BackboneSelection(ProteinSelection): bb_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - token = 'backbone' - bb_atoms = {'N', 'CA', 'C', 'O'} + + token = "backbone" + bb_atoms = {"N", "CA", "C", "O"} def _apply(self, group): atomnames = group.universe._topology.names resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ix for (nm, ix) in atomnames.namedict.items() - if nm in self.bb_atoms] + name_matches = [ + ix for (nm, ix) in atomnames.namedict.items() if nm in self.bb_atoms + ] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ix for (nm, ix) in resnames.namedict.items() - if nm in self.prot_res] + resname_matches = [ + ix for (nm, ix) in resnames.namedict.items() if nm in self.prot_res + ] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1185,7 +1336,8 @@ class NucleicBackboneSelection(NucleicSelection): bb_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - token = 'nucleicbackbone' + + token = "nucleicbackbone" bb_atoms = {"P", "C5'", "C3'", "O3'", "O5'"} def _apply(self, group): @@ -1193,14 +1345,16 @@ def _apply(self, group): resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ix for (nm, ix) in atomnames.namedict.items() - if nm in self.bb_atoms] + name_matches = [ + ix for (nm, ix) in atomnames.namedict.items() if nm in self.bb_atoms + ] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ix for (nm, ix) in resnames.namedict.items() - if nm in self.nucl_res] + resname_matches = [ + ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res + ] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1220,25 +1374,42 @@ class BaseSelection(NucleicSelection): base_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - token = 'nucleicbase' + + token = "nucleicbase" base_atoms = { - 'N9', 'N7', 'C8', 'C5', 'C4', 'N3', 'C2', 'N1', 'C6', - 'O6', 'N2', 'N6', - 'O2', 'N4', 'O4', 'C5M'} + "N9", + "N7", + "C8", + "C5", + "C4", + "N3", + "C2", + "N1", + "C6", + "O6", + "N2", + "N6", + "O2", + "N4", + "O4", + "C5M", + } def _apply(self, group): atomnames = group.universe._topology.names resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ix for (nm, ix) in atomnames.namedict.items() - if nm in self.base_atoms] + name_matches = [ + ix for (nm, ix) in atomnames.namedict.items() if nm in self.base_atoms + ] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ix for (nm, ix) in resnames.namedict.items() - if nm in self.nucl_res] + resname_matches = [ + ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res + ] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1253,7 +1424,8 @@ class NucleicSugarSelection(NucleicSelection): sug_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - token = 'nucleicsugar' + + token = "nucleicsugar" sug_atoms = {"C1'", "C2'", "C3'", "C4'", "O4'"} def _apply(self, group): @@ -1261,14 +1433,16 @@ def _apply(self, group): resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ix for (nm, ix) in atomnames.namedict.items() - if nm in self.sug_atoms] + name_matches = [ + ix for (nm, ix) in atomnames.namedict.items() if nm in self.sug_atoms + ] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ix for (nm, ix) in resnames.namedict.items() - if nm in self.nucl_res] + resname_matches = [ + ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res + ] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1284,30 +1458,34 @@ class PropertySelection(Selection): Added ``atol`` and ``rtol`` keywords to control ``np.isclose`` tolerance. """ - token = 'prop' - ops = dict([ - ('>', np.greater), - ('<', np.less), - ('>=', np.greater_equal), - ('<=', np.less_equal), - ('==', np.isclose), - ('!=', np.not_equal), - ]) + + token = "prop" + ops = dict( + [ + (">", np.greater), + ("<", np.less), + (">=", np.greater_equal), + ("<=", np.less_equal), + ("==", np.isclose), + ("!=", np.not_equal), + ] + ) # order here is important, need to check <= before < so the # larger (in terms of string length) symbol is considered first - _op_symbols = ('<=', '>=', '==', '!=', '<', '>') + _op_symbols = ("<=", ">=", "==", "!=", "<", ">") # symbols to replace with when flipping # eg 6 > x -> x <= 6, 5 == x -> x == 5 opposite_ops = { - '==': '==', '!=': '!=', - '<': '>=', '>=': '<', - '>': '<=', '<=': '>', + "==": "==", + "!=": "!=", + "<": ">=", + ">=": "<", + ">": "<=", + "<=": ">", } - props = {"x": "positions", - "y": "positions", - "z": "positions"} + props = {"x": "positions", "y": "positions", "z": "positions"} def __init__(self, parser, tokens): """ @@ -1365,14 +1543,13 @@ def __init__(self, parser, tokens): try: self.operator = self.ops[oper] except KeyError: - errmsg = (f"Invalid operator : '{oper}' Use one of : " - f"'{self.ops.keys()}'") + errmsg = f"Invalid operator : '{oper}' Use one of : " f"'{self.ops.keys()}'" raise ValueError(errmsg) from None else: if oper == "==": - self.operator = functools.partial(self.operator, - atol=parser.atol, - rtol=parser.rtol) + self.operator = functools.partial( + self.operator, atol=parser.atol, rtol=parser.rtol + ) self.value = float(value) def _apply(self, group): @@ -1387,7 +1564,7 @@ def _apply(self, group): raise SelectionError(errmsg) from None try: - col = {'x': 0, 'y': 1, 'z': 2}[self.prop] + col = {"x": 0, "y": 1, "z": 2}[self.prop] except KeyError: pass else: @@ -1409,26 +1586,26 @@ class SameSelection(Selection): :code:`"segindices"` (see #2669 and #2672) """ - token = 'same' + token = "same" precedence = 1 prop_trans = { - 'fragment': None, - 'x': None, - 'y': None, - 'z': None, - 'residue': 'resindices', - 'segment': 'segindices', - 'name': 'names', - 'type': 'types', - 'resname': 'resnames', - 'resid': 'resids', - 'segid': 'segids', - 'mass': 'masses', - 'charge': 'charges', - 'radius': 'radii', - 'bfactor': 'bfactors', - 'resnum': 'resnums', + "fragment": None, + "x": None, + "y": None, + "z": None, + "residue": "resindices", + "segment": "segindices", + "name": "names", + "type": "types", + "resname": "resnames", + "resid": "resids", + "segid": "segids", + "mass": "masses", + "charge": "charges", + "radius": "radii", + "bfactor": "bfactors", + "resnum": "resnums", } def __init__(self, parser, tokens): @@ -1436,9 +1613,11 @@ def __init__(self, parser, tokens): prop = tokens.popleft() if prop not in self.prop_trans: - raise ValueError("Unknown same property : {0}" - "Choose one of : {1}" - "".format(prop, self.prop_trans.keys())) + raise ValueError( + "Unknown same property : {0}" + "Choose one of : {1}" + "".format(prop, self.prop_trans.keys()) + ) self.prop = prop parser.expect("as") self.sel = parser.parse_expression(self.precedence) @@ -1450,7 +1629,7 @@ def _apply(self, group): return group[[]] # empty selection # Fragment must come before self.prop_trans lookups! - if self.prop == 'fragment': + if self.prop == "fragment": # Combine all fragments together, then check where group # indices are same as fragment(s) indices allfrags = functools.reduce(lambda x, y: x + y, res.fragments) @@ -1459,7 +1638,7 @@ def _apply(self, group): return group[mask] # [xyz] must come before self.prop_trans lookups too! try: - pos_idx = {'x': 0, 'y': 1, 'z': 2}[self.prop] + pos_idx = {"x": 0, "y": 1, "z": 2}[self.prop] except KeyError: # The self.prop string was already checked, # so don't need error checking here. @@ -1474,8 +1653,7 @@ def _apply(self, group): pos = group.positions[:, pos_idx] # isclose only does one value at a time - mask = np.vstack([np.isclose(pos, v) - for v in vals]).any(axis=0) + mask = np.vstack([np.isclose(pos, v) for v in vals]).any(axis=0) return group[mask] @@ -1497,7 +1675,8 @@ class SelectionParser(object): | resid [value] | name [value] | type [value] - """ + """ + # Borg pattern: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531 _shared_state = {} @@ -1513,10 +1692,20 @@ def expect(self, token): else: raise SelectionError( "Unexpected token: '{0}' Expected: '{1}'" - "".format(self.tokens[0], token)) - - def parse(self, selectstr, selgroups, periodic=None, atol=1e-08, - rtol=1e-05, sorted=True, rdkit_kwargs=None, smarts_kwargs=None): + "".format(self.tokens[0], token) + ) + + def parse( + self, + selectstr, + selgroups, + periodic=None, + atol=1e-08, + rtol=1e-05, + sorted=True, + rdkit_kwargs=None, + smarts_kwargs=None, + ): """Create a Selection object from a string. Parameters @@ -1570,19 +1759,22 @@ def parse(self, selectstr, selgroups, periodic=None, atol=1e-08, self.selectstr = selectstr self.selgroups = selgroups - tokens = selectstr.replace('(', ' ( ').replace(')', ' ) ') + tokens = selectstr.replace("(", " ( ").replace(")", " ) ") self.tokens = collections.deque(tokens.split() + [None]) parsetree = self.parse_expression(0) if self.tokens[0] is not None: raise SelectionError( "Unexpected token at end of selection string: '{0}'" - "".format(self.tokens[0])) + "".format(self.tokens[0]) + ) return parsetree def parse_expression(self, p): exp1 = self._parse_subexp() - while (self.tokens[0] in _OPERATIONS and - _OPERATIONS[self.tokens[0]].precedence >= p): + while ( + self.tokens[0] in _OPERATIONS + and _OPERATIONS[self.tokens[0]].precedence >= p + ): op = _OPERATIONS[self.tokens.popleft()] q = 1 + op.precedence exp2 = self.parse_expression(q) @@ -1592,9 +1784,9 @@ def parse_expression(self, p): def _parse_subexp(self): op = self.tokens.popleft() - if op == '(': + if op == "(": exp = self.parse_expression(0) - self.expect(')') + self.expect(")") return exp try: @@ -1611,8 +1803,9 @@ def _parse_subexp(self): Parser = SelectionParser() # create a module container to avoid name clashes of autogenerated classes -_selectors = types.ModuleType(f"{__name__}._selectors", - doc="Automatically generated selectors") +_selectors = types.ModuleType( + f"{__name__}._selectors", doc="Automatically generated selectors" +) # stick it in sys.modules so pickle can find it sys.modules[_selectors.__name__] = _selectors @@ -1667,7 +1860,7 @@ def gen_selection_class(singular, attrname, dtype, per_object): >>> gen_selection_class("resname", "resnames", object, "residue") - + Simply generating this selector is sufficient for the keyword to be accessible by :meth:`~MDAnalysis.core.universe.Universe.select_atoms`, as that is automatically handled by @@ -1679,12 +1872,15 @@ def gen_selection_class(singular, attrname, dtype, per_object): .. versionadded:: 2.0.0 """ - basedct = {"token": singular, "field": attrname, - # manually make modules the _selectors wrapper - "__module__": _selectors.__name__} + basedct = { + "token": singular, + "field": attrname, + # manually make modules the _selectors wrapper + "__module__": _selectors.__name__, + } name = f"{singular.capitalize()}Selection" - if dtype == 'U1': # order is important here, U1 will trip up issubclass + if dtype == "U1": # order is important here, U1 will trip up issubclass basecls = SingleCharSelection elif issubclass(dtype, bool): basecls = BoolSelection @@ -1701,9 +1897,11 @@ def gen_selection_class(singular, attrname, dtype, per_object): else: basedct["level"] = "ix" else: - raise ValueError(f"No base class defined for dtype {dtype}. " - "Define a Selection class manually by " - "subclassing core.selection.Selection") + raise ValueError( + f"No base class defined for dtype {dtype}. " + "Define a Selection class manually by " + "subclassing core.selection.Selection" + ) cls = type(name, (basecls,), basedct) setattr(_selectors, name, cls) # stick it in _selectors diff --git a/package/MDAnalysis/core/topology.py b/package/MDAnalysis/core/topology.py index dffff294d3..59275a8314 100644 --- a/package/MDAnalysis/core/topology.py +++ b/package/MDAnalysis/core/topology.py @@ -601,10 +601,7 @@ def add_Residue(self, segment, **new_attrs): missing = ( attr.singular for attr in self.attrs - if ( - attr.per_object == "residue" - and attr.singular not in new_attrs - ) + if (attr.per_object == "residue" and attr.singular not in new_attrs) ) raise NoDataError( "Missing the following attributes for the new" diff --git a/package/MDAnalysis/core/topologyattrs.py b/package/MDAnalysis/core/topologyattrs.py index 359bd20c9c..83a5ee10e1 100644 --- a/package/MDAnalysis/core/topologyattrs.py +++ b/package/MDAnalysis/core/topologyattrs.py @@ -396,9 +396,7 @@ def __init__(cls, name, bases, classdict): if dtype is not None: per_obj = classdict.get("per_object", bases[0].per_object) try: - selection.gen_selection_class( - singular, attrname, dtype, per_obj - ) + selection.gen_selection_class(singular, attrname, dtype, per_obj) except ValueError: msg = ( "A selection keyword could not be " @@ -476,9 +474,7 @@ def _gen_initial_values(n_atoms, n_residues, n_segments): raise NotImplementedError("No default values") @classmethod - def from_blank( - cls, n_atoms=None, n_residues=None, n_segments=None, values=None - ): + def from_blank(cls, n_atoms=None, n_residues=None, n_segments=None, values=None): """Create a blank version of this TopologyAttribute Parameters @@ -829,9 +825,7 @@ def _set_X(self, ag, values): newnames.append(val) newidx[i] = nextidx - self.nmidx[ag.ix] = ( - newidx # newidx either single value or same size array - ) + self.nmidx[ag.ix] = newidx # newidx either single value or same size array if newnames: self.name_lookup = np.concatenate([self.name_lookup, newnames]) self.values = self.name_lookup[self.nmidx] @@ -954,8 +948,7 @@ def phi_selections(residues, c_name="C", n_name="N", ca_name="CA"): keep_prev = [sum(r.atoms.names == c_name) == 1 for r in prev] keep_res = [ - all(sum(r.atoms.names == n) == 1 for n in ncac_names) - for r in residues + all(sum(r.atoms.names == n) == 1 for n in ncac_names) for r in residues ] keep = np.array(keep_prev) & np.array(keep_res) keep[invalid] = False @@ -1146,8 +1139,7 @@ def psi_selections(residues, c_name="C", n_name="N", ca_name="CA"): keep_nxt = [sum(r.atoms.names == n_name) == 1 for r in nxt] keep_res = [ - all(sum(r.atoms.names == n) == 1 for n in ncac_names) - for r in residues + all(sum(r.atoms.names == n) == 1 for n in ncac_names) for r in residues ] keep = np.array(keep_nxt) & np.array(keep_res) nxt = nxt[keep] @@ -1259,12 +1251,9 @@ def omega_selections(residues, c_name="C", n_name="N", ca_name="CA"): nxtatoms = [ca_name, n_name] resatoms = [ca_name, c_name] - keep_nxt = [ - all(sum(r.atoms.names == n) == 1 for n in nxtatoms) for r in nxt - ] + keep_nxt = [all(sum(r.atoms.names == n) == 1 for n in nxtatoms) for r in nxt] keep_res = [ - all(sum(r.atoms.names == n) == 1 for n in resatoms) - for r in residues + all(sum(r.atoms.names == n) == 1 for n in resatoms) for r in residues ] keep = np.array(keep_nxt) & np.array(keep_res) nxt = nxt[keep] @@ -1766,13 +1755,9 @@ def moment_of_inertia(group, wrap=False, unwrap=False, compound="group"): """ atomgroup = group.atoms - com = atomgroup.center_of_mass( - wrap=wrap, unwrap=unwrap, compound=compound - ) + com = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) if compound != "group": - com = (com * group.masses[:, None]).sum( - axis=0 - ) / group.masses.sum() + com = (com * group.masses[:, None]).sum(axis=0) / group.masses.sum() if wrap: pos = atomgroup.pack_into_box(inplace=False) - com @@ -1903,9 +1888,7 @@ def _gyration(recenteredpos, masses): atomgroup = group.atoms masses = atomgroup.masses - com = atomgroup.center_of_mass( - wrap=wrap, unwrap=unwrap, compound=compound - ) + com = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) if compound == "group": if wrap: @@ -2040,8 +2023,7 @@ def asphericity(group, wrap=False, unwrap=False, compound="group"): ) else: shape = (3.0 / 2.0) * ( - np.sum((eig_vals - np.mean(eig_vals)) ** 2) - / np.sum(eig_vals) ** 2 + np.sum((eig_vals - np.mean(eig_vals)) ** 2) / np.sum(eig_vals) ** 2 ) return shape @@ -2125,9 +2107,7 @@ def align_principal_axis(group, axis, vector): # print "axis = %r, angle = %f deg" % (ax, angle) return group.rotateby(angle, ax) - transplants[GroupBase].append( - ("align_principal_axis", align_principal_axis) - ) + transplants[GroupBase].append(("align_principal_axis", align_principal_axis)) # TODO: update docs to property doc @@ -2284,9 +2264,7 @@ def total_charge(group, compound="group"): @warn_if_not_unique @_pbc_to_wrap @check_wrap_and_unwrap - def dipole_vector( - group, wrap=False, unwrap=False, compound="group", center="mass" - ): + def dipole_vector(group, wrap=False, unwrap=False, compound="group", center="mass"): r"""Dipole vector of the group. .. math:: @@ -2352,9 +2330,7 @@ def dipole_vector( if center == "mass": masses = atomgroup.masses - ref = atomgroup.center_of_mass( - wrap=wrap, unwrap=unwrap, compound=compound - ) + ref = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) elif center == "charge": ref = atomgroup.center_of_charge( wrap=wrap, unwrap=unwrap, compound=compound @@ -2380,9 +2356,7 @@ def dipole_vector( ) else: recenteredpos = atomgroup.positions - ref - dipole_vector = np.einsum( - "ij,ij->j", recenteredpos, charges[:, np.newaxis] - ) + dipole_vector = np.einsum("ij,ij->j", recenteredpos, charges[:, np.newaxis]) else: (atom_masks, compound_masks, n_compounds) = ( atomgroup._split_by_compound_indices(compound) @@ -2466,13 +2440,9 @@ def dipole_moment(group, **kwargs): dipole_vector = atomgroup.dipole_vector(**kwargs) if len(dipole_vector.shape) > 1: - dipole_moment = np.sqrt( - np.einsum("ij,ij->i", dipole_vector, dipole_vector) - ) + dipole_moment = np.sqrt(np.einsum("ij,ij->i", dipole_vector, dipole_vector)) else: - dipole_moment = np.sqrt( - np.einsum("i,i->", dipole_vector, dipole_vector) - ) + dipole_moment = np.sqrt(np.einsum("i,i->", dipole_vector, dipole_vector)) return dipole_moment @@ -2565,9 +2535,7 @@ def __quadrupole_tensor(recenteredpos, charges): if center == "mass": masses = atomgroup.masses - ref = atomgroup.center_of_mass( - wrap=wrap, unwrap=unwrap, compound=compound - ) + ref = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) elif center == "charge": ref = atomgroup.center_of_charge( wrap=wrap, unwrap=unwrap, compound=compound @@ -2685,9 +2653,7 @@ def __quadrupole_moment(tensor): if len(quad_tensor.shape) == 2: quad_moment = __quadrupole_moment(quad_tensor) else: - quad_moment = np.array( - [__quadrupole_moment(x) for x in quad_tensor] - ) + quad_moment = np.array([__quadrupole_moment(x) for x in quad_tensor]) return quad_moment @@ -3011,9 +2977,7 @@ def sequence(self, **kwargs): ) ) try: - sequence = "".join( - [convert_aa_code(r) for r in self.residues.resnames] - ) + sequence = "".join([convert_aa_code(r) for r in self.residues.resnames]) except KeyError as err: errmsg = ( f"AtomGroup contains a residue name '{err.message}' that" @@ -3146,14 +3110,13 @@ def _check_connection_values(func): @functools.wraps(func) def wrapper(self, values, *args, **kwargs): if not all( - len(x) == self._n_atoms - and all(isinstance(y, (int, np.integer)) for y in x) + len(x) == self._n_atoms and all(isinstance(y, (int, np.integer)) for y in x) for x in values ): raise ValueError( - ( - "{} must be an iterable of tuples with {}" " atom indices" - ).format(self.attrname, self._n_atoms) + ("{} must be an iterable of tuples with {}" " atom indices").format( + self.attrname, self._n_atoms + ) ) clean = [] for v in values: @@ -3231,9 +3194,7 @@ def _bondDict(self): """Lazily built mapping of atoms:bonds""" bd = defaultdict(list) - for b, t, g, o in zip( - self.values, self.types, self._guessed, self.order - ): + for b, t, g, o in zip(self.values, self.types, self._guessed, self.order): for a in b: bd[a].append((b, t, g, o)) return bd @@ -3252,9 +3213,7 @@ def get_atoms(self, ag): """ try: - unique_bonds = set( - itertools.chain(*[self._bondDict[a] for a in ag.ix]) - ) + unique_bonds = set(itertools.chain(*[self._bondDict[a] for a in ag.ix])) except TypeError: # maybe we got passed an Atom unique_bonds = self._bondDict[ag.ix] diff --git a/package/MDAnalysis/core/topologyobjects.py b/package/MDAnalysis/core/topologyobjects.py index fcc37be624..14d44a4c8c 100644 --- a/package/MDAnalysis/core/topologyobjects.py +++ b/package/MDAnalysis/core/topologyobjects.py @@ -603,9 +603,7 @@ def __init__( # guess what I am # difference between dihedral and improper # not really important - self.btype = {2: "bond", 3: "angle", 4: "dihedral"}[ - len(bondidx[0]) - ] + self.btype = {2: "bond", 3: "angle", 4: "dihedral"}[len(bondidx[0])] elif btype in _BTYPE_TO_SHAPE: self.btype = btype else: @@ -638,8 +636,7 @@ def __init__( # Create vertical AtomGroups self._ags = [ - universe.atoms[self._bix[:, i]] - for i in range(self._bix.shape[1]) + universe.atoms[self._bix[:, i]] for i in range(self._bix.shape[1]) ] else: # Empty TopologyGroup @@ -816,15 +813,11 @@ def __add__(self, other): np.concatenate([self.indices, other.indices[None, :]]), self.universe, btype=self.btype, - type=np.concatenate( - [self._bondtypes, np.array([other._bondtype])] - ), + type=np.concatenate([self._bondtypes, np.array([other._bondtype])]), guessed=np.concatenate( [self._guessed, np.array([other.is_guessed])] ), - order=np.concatenate( - [self._order, np.array([other.order])] - ), + order=np.concatenate([self._order, np.array([other.order])]), ) else: # add TG to me diff --git a/package/MDAnalysis/core/universe.py b/package/MDAnalysis/core/universe.py index 6dbc063f10..e315c8dc70 100644 --- a/package/MDAnalysis/core/universe.py +++ b/package/MDAnalysis/core/universe.py @@ -80,14 +80,28 @@ from ..lib.mdamath import find_fragments from . import groups from ._get_readers import get_reader_for, get_parser_for -from .groups import (ComponentBase, GroupBase, - Atom, Residue, Segment, - AtomGroup, ResidueGroup, SegmentGroup) +from .groups import ( + ComponentBase, + GroupBase, + Atom, + Residue, + Segment, + AtomGroup, + ResidueGroup, + SegmentGroup, +) from .topology import Topology from .topologyattrs import ( - AtomAttr, ResidueAttr, SegmentAttr, - Segindices, Segids, Resindices, Resids, Atomindices, - BFACTOR_WARNING, _Connection + AtomAttr, + ResidueAttr, + SegmentAttr, + Segindices, + Segids, + Resindices, + Resids, + Atomindices, + BFACTOR_WARNING, + _Connection, ) from .topologyobjects import TopologyObject from ..guesser.base import get_guesser @@ -116,8 +130,8 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): atom_attrindices = [ idx for idx, each_attr in enumerate(top.attrs) - if (Residue not in each_attr.target_classes) and - (not isinstance(each_attr, Atomindices)) + if (Residue not in each_attr.target_classes) + and (not isinstance(each_attr, Atomindices)) ] attrs = [top.attrs[each_attr] for each_attr in atom_attrindices] @@ -126,17 +140,17 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): idx for idx, each_attr in enumerate(top.attrs) if ( - (Residue in each_attr.target_classes) and - (Segment not in each_attr.target_classes) and - (not isinstance(each_attr, Resids)) and - (not isinstance(each_attr, Resindices)) + (Residue in each_attr.target_classes) + and (Segment not in each_attr.target_classes) + and (not isinstance(each_attr, Resids)) + and (not isinstance(each_attr, Resindices)) ) ] # residue level attributes except resids and resindices res_criteria = [atomwise_resids, atomwise_segids] + [ getattr(universe.atoms, top.attrs[each_attr].attrname) for each_attr in residue_attrindices - if top.attrs[each_attr].attrname != 'resnums' + if top.attrs[each_attr].attrname != "resnums" ] res_to_squash = [atomwise_resids, atomwise_segids] + [ @@ -168,11 +182,11 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): each_attr for each_attr in top.attrs if ( - (Segment in each_attr.target_classes) and - (not isinstance(each_attr, Segids)) and - (not isinstance(each_attr, Atomindices)) and - (not isinstance(each_attr, Resindices)) and - (not isinstance(each_attr, Segindices)) + (Segment in each_attr.target_classes) + and (not isinstance(each_attr, Segids)) + and (not isinstance(each_attr, Atomindices)) + and (not isinstance(each_attr, Resindices)) + and (not isinstance(each_attr, Segindices)) ) ] @@ -197,15 +211,15 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): def _check_file_like(topology): if isstream(topology): - if hasattr(topology, 'name'): + if hasattr(topology, "name"): _name = topology.name else: _name = None return NamedStream(topology, _name) return topology -def _topology_from_file_like(topology_file, topology_format=None, - **kwargs): + +def _topology_from_file_like(topology_file, topology_format=None, **kwargs): parser = get_parser_for(topology_file, format=topology_format) try: @@ -215,20 +229,22 @@ def _topology_from_file_like(topology_file, topology_format=None, # There are 2 kinds of errors that might be raised here: # one because the file isn't present # or the permissions are bad, second when the parser fails - if (err.errno is not None and - errno.errorcode[err.errno] in ['ENOENT', 'EACCES']): + if err.errno is not None and errno.errorcode[err.errno] in ["ENOENT", "EACCES"]: # Runs if the error is propagated due to no permission / file not found raise sys.exc_info()[1] from err else: # Runs when the parser fails - raise IOError("Failed to load from the topology file {0}" - " with parser {1}.\n" - "Error: {2}".format(topology_file, parser, err)) + raise IOError( + "Failed to load from the topology file {0}" + " with parser {1}.\n" + "Error: {2}".format(topology_file, parser, err) + ) except (ValueError, NotImplementedError) as err: raise ValueError( "Failed to construct topology from file {0}" " with parser {1}.\n" - "Error: {2}".format(topology_file, parser, err)) + "Error: {2}".format(topology_file, parser, err) + ) return topology @@ -241,18 +257,20 @@ def _resolve_formats(*coordinates, format=None, topology_format=None): return format, topology_format -def _resolve_coordinates(filename, *coordinates, format=None, - all_coordinates=False): +def _resolve_coordinates(filename, *coordinates, format=None, all_coordinates=False): if all_coordinates or not coordinates and filename is not None: try: get_reader_for(filename, format=format) except (ValueError, TypeError): - warnings.warn('No coordinate reader found for {}. Skipping ' - 'this file.'.format(filename)) + warnings.warn( + "No coordinate reader found for {}. Skipping " + "this file.".format(filename) + ) else: coordinates = (filename,) + coordinates return coordinates + def _generate_from_topology(universe): # generate Universe version of each class # AG, RG, SG, A, R, S @@ -270,11 +288,9 @@ def _generate_from_topology(universe): # once.) universe.atoms = AtomGroup(np.arange(universe._topology.n_atoms), universe) - universe.residues = ResidueGroup( - np.arange(universe._topology.n_residues), universe) + universe.residues = ResidueGroup(np.arange(universe._topology.n_residues), universe) - universe.segments = SegmentGroup( - np.arange(universe._topology.n_segments), universe) + universe.segments = SegmentGroup(np.arange(universe._topology.n_segments), universe) class Universe(object): @@ -396,7 +412,7 @@ class Universe(object): method instead. If passed into `guess_TopologyAttrs`, it will override the values set during Guesser creation. - + transformations: function or list, ``None``, default ``None`` Provide a list of transformations that you wish to apply to the trajectory upon reading. Transformations can be found in @@ -491,60 +507,82 @@ class Universe(object): API to set residues/segments based on the atomwise resids/segids. """ - def __init__(self, topology=None, *coordinates, all_coordinates=False, - format=None, topology_format=None, transformations=None, - guess_bonds=False, vdwradii=None, fudge_factor=0.55, - lower_bound=0.1, in_memory=False, context='default', - to_guess=('types', 'masses'), force_guess=(), - in_memory_step=1, **kwargs): + + def __init__( + self, + topology=None, + *coordinates, + all_coordinates=False, + format=None, + topology_format=None, + transformations=None, + guess_bonds=False, + vdwradii=None, + fudge_factor=0.55, + lower_bound=0.1, + in_memory=False, + context="default", + to_guess=("types", "masses"), + force_guess=(), + in_memory_step=1, + **kwargs, + ): self._trajectory = None # managed attribute holding Reader - self._cache = {'_valid': {}} + self._cache = {"_valid": {}} self.atoms = None self.residues = None self.segments = None self.filename = None self._context = get_guesser(context) self._kwargs = { - 'transformations': transformations, - 'guess_bonds': guess_bonds, - 'vdwradii': vdwradii, - 'fudge_factor': fudge_factor, - 'lower_bound': lower_bound, - 'in_memory': in_memory, - 'in_memory_step': in_memory_step, - 'format': format, - 'topology_format': topology_format, - 'all_coordinates': all_coordinates + "transformations": transformations, + "guess_bonds": guess_bonds, + "vdwradii": vdwradii, + "fudge_factor": fudge_factor, + "lower_bound": lower_bound, + "in_memory": in_memory, + "in_memory_step": in_memory_step, + "format": format, + "topology_format": topology_format, + "all_coordinates": all_coordinates, } self._kwargs.update(kwargs) - format, topology_format = _resolve_formats(*coordinates, format=format, - topology_format=topology_format) + format, topology_format = _resolve_formats( + *coordinates, format=format, topology_format=topology_format + ) if not isinstance(topology, Topology) and not topology is None: self.filename = _check_file_like(topology) - topology = _topology_from_file_like(self.filename, - topology_format=topology_format, - **kwargs) + topology = _topology_from_file_like( + self.filename, topology_format=topology_format, **kwargs + ) if topology is not None: self._topology = topology else: # point to Universe.empty instead of making empty universe - raise TypeError('Topology argument required to make Universe. ' - 'Try Universe.empty(n_atoms, ...) to construct ' - 'your own Universe.') + raise TypeError( + "Topology argument required to make Universe. " + "Try Universe.empty(n_atoms, ...) to construct " + "your own Universe." + ) _generate_from_topology(self) # make real atoms, res, segments - coordinates = _resolve_coordinates(self.filename, *coordinates, - format=format, - all_coordinates=all_coordinates) + coordinates = _resolve_coordinates( + self.filename, *coordinates, format=format, all_coordinates=all_coordinates + ) if coordinates: - self.load_new(coordinates, format=format, in_memory=in_memory, - in_memory_step=in_memory_step, **kwargs) + self.load_new( + coordinates, + format=format, + in_memory=in_memory, + in_memory_step=in_memory_step, + **kwargs, + ) if transformations: if callable(transformations): @@ -565,30 +603,35 @@ def __init__(self, topology=None, *coordinates, all_coordinates=False, "Universe instantiation. If using guess_TopologyAttrs, " "pass these kwargs to the method instead, as they will override " "the previous Context values.", - DeprecationWarning + DeprecationWarning, ) # Original behaviour is to add additionally guessed bond info # this is achieved by adding to the `to_guess` list (unliked `force_guess` # which replaces existing bonds). - to_guess = list(to_guess) + ['bonds', 'angles', 'dihedrals'] - - self.guess_TopologyAttrs( - context, to_guess, force_guess, error_if_missing=False - ) + to_guess = list(to_guess) + ["bonds", "angles", "dihedrals"] + self.guess_TopologyAttrs(context, to_guess, force_guess, error_if_missing=False) def copy(self): """Return an independent copy of this Universe""" context = self._context.copy() - new = self.__class__(self._topology.copy(), - to_guess=(), context=context) + new = self.__class__(self._topology.copy(), to_guess=(), context=context) new.trajectory = self.trajectory.copy() return new @classmethod - def empty(cls, n_atoms, n_residues=1, n_segments=1, n_frames=1, - atom_resindex=None, residue_segindex=None, - trajectory=False, velocities=False, forces=False): + def empty( + cls, + n_atoms, + n_residues=1, + n_segments=1, + n_frames=1, + atom_resindex=None, + residue_segindex=None, + trajectory=False, + velocities=False, + forces=False, + ): """Create a blank Universe Useful for building a Universe without requiring existing files, @@ -655,19 +698,24 @@ def empty(cls, n_atoms, n_residues=1, n_segments=1, n_frames=1, if atom_resindex is None and n_residues > 1: warnings.warn( - 'Residues specified but no atom_resindex given. ' - 'All atoms will be placed in first Residue.', - UserWarning) + "Residues specified but no atom_resindex given. " + "All atoms will be placed in first Residue.", + UserWarning, + ) if residue_segindex is None and n_segments > 1: warnings.warn( - 'Segments specified but no segment_resindex given. ' - 'All residues will be placed in first Segment', - UserWarning) + "Segments specified but no segment_resindex given. " + "All residues will be placed in first Segment", + UserWarning, + ) - top = Topology(n_atoms, n_residues, n_segments, - atom_resindex=atom_resindex, - residue_segindex=residue_segindex, + top = Topology( + n_atoms, + n_residues, + n_segments, + atom_resindex=atom_resindex, + residue_segindex=residue_segindex, ) u = cls(top, to_guess=()) @@ -679,8 +727,8 @@ def empty(cls, n_atoms, n_residues=1, n_segments=1, n_frames=1, # grab and attach a MemoryReader u.trajectory = get_reader_for(coords)( - coords, order='fac', n_atoms=n_atoms, - velocities=vels, forces=forces) + coords, order="fac", n_atoms=n_atoms, velocities=vels, forces=forces + ) return u @@ -693,8 +741,9 @@ def universe(self): # It is also cleaner than a weakref. return self - def load_new(self, filename, format=None, in_memory=False, - in_memory_step=1, **kwargs): + def load_new( + self, filename, format=None, in_memory=False, in_memory_step=1, **kwargs + ): """Load coordinates from `filename`. The file format of `filename` is autodetected from the file name suffix @@ -767,29 +816,34 @@ def load_new(self, filename, format=None, in_memory=False, except ValueError as err: raise TypeError( "Cannot find an appropriate coordinate reader for file '{0}'.\n" - " {1}".format(filename, err)) + " {1}".format(filename, err) + ) # supply number of atoms for readers that cannot do it for themselves - kwargs['n_atoms'] = self.atoms.n_atoms + kwargs["n_atoms"] = self.atoms.n_atoms self.trajectory = reader(filename, format=format, **kwargs) if self.trajectory.n_atoms != len(self.atoms): - raise ValueError("The topology and {form} trajectory files don't" - " have the same number of atoms!\n" - "Topology number of atoms {top_n_atoms}\n" - "Trajectory: {fname} Number of atoms {trj_n_atoms}".format( - form=self.trajectory.format, - top_n_atoms=len(self.atoms), - fname=filename, - trj_n_atoms=self.trajectory.n_atoms)) + raise ValueError( + "The topology and {form} trajectory files don't" + " have the same number of atoms!\n" + "Topology number of atoms {top_n_atoms}\n" + "Trajectory: {fname} Number of atoms {trj_n_atoms}".format( + form=self.trajectory.format, + top_n_atoms=len(self.atoms), + fname=filename, + trj_n_atoms=self.trajectory.n_atoms, + ) + ) if in_memory: self.transfer_to_memory(step=in_memory_step, **kwargs) return self - def transfer_to_memory(self, start=None, stop=None, step=None, - verbose=False, **kwargs): + def transfer_to_memory( + self, start=None, stop=None, step=None, verbose=False, **kwargs + ): """Transfer the trajectory to in memory representation. Replaces the current trajectory reader object with one of type @@ -816,9 +870,9 @@ def transfer_to_memory(self, start=None, stop=None, step=None, from ..coordinates.memory import MemoryReader if not isinstance(self.trajectory, MemoryReader): - n_frames = len(range( - *self.trajectory.check_slice_indices(start, stop, step) - )) + n_frames = len( + range(*self.trajectory.check_slice_indices(start, stop, step)) + ) n_atoms = len(self.atoms) coordinates = np.zeros((n_frames, n_atoms, 3), dtype=np.float32) ts = self.trajectory.ts @@ -828,12 +882,15 @@ def transfer_to_memory(self, start=None, stop=None, step=None, velocities = np.zeros_like(coordinates) if has_vels else None forces = np.zeros_like(coordinates) if has_fors else None - dimensions = (np.zeros((n_frames, 6), dtype=np.float32) - if has_dims else None) + dimensions = np.zeros((n_frames, 6), dtype=np.float32) if has_dims else None - for i, ts in enumerate(ProgressBar(self.trajectory[start:stop:step], - verbose=verbose, - desc="Loading frames")): + for i, ts in enumerate( + ProgressBar( + self.trajectory[start:stop:step], + verbose=verbose, + desc="Loading frames", + ) + ): np.copyto(coordinates[i], ts.positions) if has_vels: np.copyto(velocities[i], ts.velocities) @@ -853,7 +910,9 @@ def transfer_to_memory(self, start=None, stop=None, step=None, dt=self.trajectory.ts.dt * step, filename=self.trajectory.filename, velocities=velocities, - forces=forces, **kwargs) + forces=forces, + **kwargs, + ) # python 2 doesn't allow an efficient splitting of kwargs in function # argument signatures. @@ -905,8 +964,7 @@ def __repr__(self): # n_atoms=len(self.atoms), # bonds=" and {0} bonds".format(len(self.bonds)) if self.bonds else "") - return "".format( - n_atoms=len(self.atoms)) + return "".format(n_atoms=len(self.atoms)) @classmethod def _unpickle_U(cls, top, traj, context): @@ -921,8 +979,10 @@ def __reduce__(self): # __setstate__/__getstate__ will raise an error when Universe has a # transformation (that has AtomGroup inside). Use __reduce__ instead. # Universe's two "legs" of top and traj both serialise themselves. - return (self._unpickle_U, (self._topology, - self._trajectory, self._context.copy())) + return ( + self._unpickle_U, + (self._topology, self._trajectory, self._context.copy()), + ) # Properties @property @@ -1034,16 +1094,16 @@ def add_TopologyAttr(self, topologyattr, values=None): " Possible values: '{}'\n" "To raise an issue go to: " "https://github.com/MDAnalysis/mdanalysis/issues" - "".format( - topologyattr, ', '.join( - sorted(_TOPOLOGY_ATTRS.keys())))) + "".format(topologyattr, ", ".join(sorted(_TOPOLOGY_ATTRS.keys()))) + ) raise ValueError(errmsg) from None else: topologyattr = tcls.from_blank( n_atoms=self._topology.n_atoms, n_residues=self._topology.n_residues, n_segments=self._topology.n_segments, - values=values) + values=values, + ) self._topology.add_TopologyAttr(topologyattr) self._process_attr(topologyattr) @@ -1088,25 +1148,30 @@ def del_TopologyAttr(self, topologyattr): # e.g. matrix -> matrices topologyattr = topologyattr.btype + "s" except AttributeError: - raise ValueError("Topology attribute must be str or " - "TopologyAttr object or class. " - f"Given: {type(topologyattr)}") from None + raise ValueError( + "Topology attribute must be str or " + "TopologyAttr object or class. " + f"Given: {type(topologyattr)}" + ) from None try: topologyattr = _TOPOLOGY_ATTRS[topologyattr].attrname except KeyError: - attrs = ', '.join(sorted(_TOPOLOGY_ATTRS)) - errmsg = (f"Unrecognised topology attribute: '{topologyattr}'." - f" Possible values: '{attrs}'\n" - "To raise an issue go to: " - "https://github.com/MDAnalysis/mdanalysis/issues") + attrs = ", ".join(sorted(_TOPOLOGY_ATTRS)) + errmsg = ( + f"Unrecognised topology attribute: '{topologyattr}'." + f" Possible values: '{attrs}'\n" + "To raise an issue go to: " + "https://github.com/MDAnalysis/mdanalysis/issues" + ) raise ValueError(errmsg) from None try: topattr = getattr(self._topology, topologyattr) except AttributeError: - raise ValueError(f"Topology attribute {topologyattr} " - "not in Universe.") from None + raise ValueError( + f"Topology attribute {topologyattr} " "not in Universe." + ) from None self._topology.del_TopologyAttr(topattr) self._unprocess_attr(topattr) @@ -1118,30 +1183,42 @@ def _process_attr(self, attr): - Component properties - Transplant methods """ - n_dict = {'atom': self._topology.n_atoms, - 'residue': self._topology.n_residues, - 'segment': self._topology.n_segments} + n_dict = { + "atom": self._topology.n_atoms, + "residue": self._topology.n_residues, + "segment": self._topology.n_segments, + } logger.debug("_process_attr: Adding {0} to topology".format(attr)) - if (attr.per_object is not None and len(attr) != n_dict[attr.per_object]): - raise ValueError('Length of {attr} does not' - ' match number of {obj}s.\n' - 'Expect: {n:d} Have: {m:d}'.format( - attr=attr.attrname, - obj=attr.per_object, - n=n_dict[attr.per_object], - m=len(attr))) + if attr.per_object is not None and len(attr) != n_dict[attr.per_object]: + raise ValueError( + "Length of {attr} does not" + " match number of {obj}s.\n" + "Expect: {n:d} Have: {m:d}".format( + attr=attr.attrname, + obj=attr.per_object, + n=n_dict[attr.per_object], + m=len(attr), + ) + ) for cls in attr.target_classes: self._class_bases[cls]._add_prop(attr) # TODO: Try and shove this into cls._add_prop # Group transplants - for cls in (Atom, Residue, Segment, GroupBase, - AtomGroup, ResidueGroup, SegmentGroup): + for cls in ( + Atom, + Residue, + Segment, + GroupBase, + AtomGroup, + ResidueGroup, + SegmentGroup, + ): for funcname, meth in attr.transplants[cls]: setattr(self._class_bases[cls], funcname, meth) # Universe transplants - for funcname, meth in attr.transplants['Universe']: + for funcname, meth in attr.transplants["Universe"]: setattr(self.__class__, funcname, meth) def _unprocess_attr(self, attr): @@ -1241,8 +1318,9 @@ def add_Segment(self, **attrs): # return the new segment return self.segments[segidx] - def _add_topology_objects(self, object_type, values, types=None, guessed=False, - order=None): + def _add_topology_objects( + self, object_type, values, types=None, guessed=False, order=None + ): """Add new TopologyObjects to this Universe Parameters @@ -1277,7 +1355,7 @@ def _add_topology_objects(self, object_type, values, types=None, guessed=False, for x in values: if isinstance(x, (AtomGroup, TopologyObject)): if x.universe is not self: - err_msg = 'Cannot add {} from different Universes.' + err_msg = "Cannot add {} from different Universes." raise ValueError(err_msg.format(object_type)) indices.append(x.indices) else: @@ -1286,8 +1364,8 @@ def _add_topology_objects(self, object_type, values, types=None, guessed=False, all_indices = set([i for obj in indices for i in obj]) nonexistent = all_indices - set(self.atoms.indices) if nonexistent: - istr = ', '.join(map(str, nonexistent)) - err_msg = 'Cannot add {} for nonexistent atom indices: {}' + istr = ", ".join(map(str, nonexistent)) + err_msg = "Cannot add {} for nonexistent atom indices: {}" raise ValueError(err_msg.format(object_type, istr)) try: @@ -1344,22 +1422,23 @@ def add_bonds(self, values, types=None, guessed=False, order=None): .. versionadded:: 1.0.0 """ - self._add_topology_objects('bonds', values, types=types, - guessed=guessed, order=order) + self._add_topology_objects( + "bonds", values, types=types, guessed=guessed, order=order + ) self._invalidate_bond_related_caches() def _invalidate_bond_related_caches(self): """ Invalidate caches related to bonds and fragments. - + This should be called whenever the Universe's bonds are modified. .. versionadded: 2.8.0 """ # Invalidate bond-related caches - self._cache.pop('fragments', None) - self._cache['_valid'].pop('fragments', None) - self._cache['_valid'].pop('fragindices', None) + self._cache.pop("fragments", None) + self._cache["_valid"].pop("fragments", None) + self._cache["_valid"].pop("fragindices", None) def add_angles(self, values, types=None, guessed=False): """Add new Angles to this Universe. @@ -1379,8 +1458,7 @@ def add_angles(self, values, types=None, guessed=False): .. versionadded:: 1.0.0 """ - self._add_topology_objects('angles', values, types=types, - guessed=guessed) + self._add_topology_objects("angles", values, types=types, guessed=guessed) def add_dihedrals(self, values, types=None, guessed=False): """Add new Dihedrals to this Universe. @@ -1401,8 +1479,7 @@ def add_dihedrals(self, values, types=None, guessed=False): .. versionadded:: 1.0.0 """ - self._add_topology_objects('dihedrals', values, types=types, - guessed=guessed) + self._add_topology_objects("dihedrals", values, types=types, guessed=guessed) def add_impropers(self, values, types=None, guessed=False): """Add new Impropers to this Universe. @@ -1423,8 +1500,7 @@ def add_impropers(self, values, types=None, guessed=False): .. versionadded:: 1.0.0 """ - self._add_topology_objects('impropers', values, types=types, - guessed=guessed) + self._add_topology_objects("impropers", values, types=types, guessed=guessed) def _delete_topology_objects(self, object_type, values): """Delete TopologyObjects from this Universe @@ -1445,7 +1521,7 @@ def _delete_topology_objects(self, object_type, values): for x in values: if isinstance(x, (AtomGroup, TopologyObject)): if x.universe is not self: - err_msg = 'Cannot delete {} from different Universes.' + err_msg = "Cannot delete {} from different Universes." raise ValueError(err_msg.format(object_type)) indices.append(x.indices) else: @@ -1454,7 +1530,7 @@ def _delete_topology_objects(self, object_type, values): try: attr = getattr(self._topology, object_type) except AttributeError: - raise ValueError('There are no {} to delete'.format(object_type)) + raise ValueError("There are no {} to delete".format(object_type)) attr._delete_bonds(indices) def delete_bonds(self, values): @@ -1494,7 +1570,7 @@ def delete_bonds(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects('bonds', values) + self._delete_topology_objects("bonds", values) self._invalidate_bond_related_caches() def delete_angles(self, values): @@ -1511,7 +1587,7 @@ def delete_angles(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects('angles', values) + self._delete_topology_objects("angles", values) def delete_dihedrals(self, values): """Delete Dihedrals from this Universe. @@ -1527,7 +1603,7 @@ def delete_dihedrals(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects('dihedrals', values) + self._delete_topology_objects("dihedrals", values) def delete_impropers(self, values): """Delete Impropers from this Universe. @@ -1543,7 +1619,7 @@ def delete_impropers(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects('impropers', values) + self._delete_topology_objects("impropers", values) # TODO: Maybe put this as a Bond attribute transplant # Problems: Can we transplant onto Universe? @@ -1555,7 +1631,7 @@ def delete_impropers(self, values): # Attribute (ie, 2 for the price of 1) # Fragments then gets its own Class/namespace/jazz. @property - @cached('fragments') + @cached("fragments") def _fragdict(self): """ .. versionadded:: 0.9.0 @@ -1576,7 +1652,7 @@ def _fragdict(self): frags = tuple([AtomGroup(np.sort(ix), self) for ix in frag_indices]) fragdict = {} - fraginfo = collections.namedtuple('fraginfo', 'ix, fragment') + fraginfo = collections.namedtuple("fraginfo", "ix, fragment") for i, f in enumerate(frags): for a in f: fragdict[a.ix] = fraginfo(i, f) @@ -1655,29 +1731,38 @@ def from_smiles( except ImportError as e: raise ImportError( "Creating a Universe from a SMILES string requires RDKit but " - "it does not appear to be installed") from e + "it does not appear to be installed" + ) from e mol = Chem.MolFromSmiles(smiles, sanitize=sanitize) if mol is None: - raise SyntaxError('Error while parsing SMILES {0}'.format(smiles)) + raise SyntaxError("Error while parsing SMILES {0}".format(smiles)) if addHs: mol = Chem.AddHs(mol) if generate_coordinates: if not addHs: - raise ValueError("Generating coordinates requires adding " - "hydrogens with `addHs=True`") + raise ValueError( + "Generating coordinates requires adding " + "hydrogens with `addHs=True`" + ) numConfs = rdkit_kwargs.pop("numConfs", numConfs) if not (isinstance(numConfs, int) and numConfs > 0): - raise SyntaxError("numConfs must be a non-zero positive " - "integer instead of {0}".format(numConfs)) + raise SyntaxError( + "numConfs must be a non-zero positive " + "integer instead of {0}".format(numConfs) + ) AllChem.EmbedMultipleConfs(mol, numConfs, **rdkit_kwargs) return cls(mol, **kwargs) def guess_TopologyAttrs( - self, context=None, to_guess=None, force_guess=None, - error_if_missing=True, **kwargs + self, + context=None, + to_guess=None, + force_guess=None, + error_if_missing=True, + **kwargs, ): """ Guess and add attributes through a specific context-aware guesser. @@ -1697,7 +1782,7 @@ def guess_TopologyAttrs( However, starting with release 3.0 **no guessing will be done by default** and it will be up to the user to request guessing using ``to_guess`` and ``force_guess``. - + force_guess: Optional[list[str]] TopologyAttrs in this list will be force guessed. If the TopologyAttr does not already exist in the Universe, this has no @@ -1746,7 +1831,8 @@ def guess_TopologyAttrs( # Set of all Connectivity related attribute names # used to special case attribute replacement after calling the guesser objects = set( - topattr.attrname for topattr in _TOPOLOGY_ATTRS.values() + topattr.attrname + for topattr in _TOPOLOGY_ATTRS.values() if issubclass(topattr, _Connection) ) @@ -1754,25 +1840,25 @@ def guess_TopologyAttrs( # from guesser methods if self._topology.n_atoms > 0: - topology_attrs = [att.attrname for att in - self._topology.read_attributes] + topology_attrs = [att.attrname for att in self._topology.read_attributes] common_attrs = set(to_guess) & set(topology_attrs) common_attrs = ", ".join(attr for attr in common_attrs) if len(common_attrs) > 0: logger.info( - f'The attribute(s) {common_attrs} have already been read ' - 'from the topology file. The guesser will ' - 'only guess empty values for this attribute, ' - 'if any exists. To overwrite it by completely ' - 'guessed values, you can pass the attribute to' - ' the force_guess parameter instead of ' - 'the to_guess one') + f"The attribute(s) {common_attrs} have already been read " + "from the topology file. The guesser will " + "only guess empty values for this attribute, " + "if any exists. To overwrite it by completely " + "guessed values, you can pass the attribute to" + " the force_guess parameter instead of " + "the to_guess one" + ) for attr in total_guess: if guesser.is_guessable(attr): - fg = attr in force_guess + fg = attr in force_guess try: values = guesser.guess_attr(attr, fg) except NoDataError as e: @@ -1791,24 +1877,22 @@ def guess_TopologyAttrs( group = getattr(self.atoms, attr) self._delete_topology_objects(attr, group) # this method appends any new bonds in values to existing bonds - self._add_topology_objects( - attr, values, guessed=True) + self._add_topology_objects(attr, values, guessed=True) if attr == "bonds": self._invalidate_bond_related_caches() else: guessed_attr = _TOPOLOGY_ATTRS[attr](values, True) self.add_TopologyAttr(guessed_attr) - logger.info( - f'attribute {attr} has been guessed' - ' successfully.') + logger.info(f"attribute {attr} has been guessed" " successfully.") else: - raise ValueError(f'{context} guesser can not guess the' - f' following attribute: {attr}') + raise ValueError( + f"{context} guesser can not guess the" + f" following attribute: {attr}" + ) else: - warnings.warn('Can not guess attributes ' - 'for universe with 0 atoms') + warnings.warn("Can not guess attributes " "for universe with 0 atoms") def set_groups(self, atomwise_resids=None, atomwise_segids=None): """Set the groups (`ResidueGroup`, `SegmentGroup`) of the Universe @@ -1864,8 +1948,10 @@ def set_groups(self, atomwise_resids=None, atomwise_segids=None): .. versionadded:: 2.10.0 """ if (atomwise_resids is None) and (atomwise_segids is None): - warnings.warn("Not setting groups. Please provide atomwise_resids or " - "atomwise_segids.") + warnings.warn( + "Not setting groups. Please provide atomwise_resids or " + "atomwise_segids." + ) return # resids @@ -1877,12 +1963,15 @@ def set_groups(self, atomwise_resids=None, atomwise_segids=None): if len(atomwise_resids) != self.atoms.n_atoms: raise ValueError( "The length of atomwise_resids should be the same as " - "the number of atoms in the universe.") + "the number of atoms in the universe." + ) self.atomwise_resids_orig = self.atoms.resids - logger.info("The new resids replaces the current one. " - "The original resids is stored in " - "atomwise_resids_orig.") + logger.info( + "The new resids replaces the current one. " + "The original resids is stored in " + "atomwise_resids_orig." + ) # segids if atomwise_segids is None: @@ -1893,19 +1982,22 @@ def set_groups(self, atomwise_resids=None, atomwise_segids=None): if len(atomwise_segids) != self.atoms.n_atoms: raise ValueError( "The length of atomwise_segids should be the same as " - "the number of atoms in the universe.") + "the number of atoms in the universe." + ) self.atomwise_segids_orig = self.atoms.segids - logger.info("The new resids replaces the current one. " - "The original segids is stored in " - "atomwise_segids_orig.") + logger.info( + "The new resids replaces the current one. " + "The original segids is stored in " + "atomwise_segids_orig." + ) atomwise_resids = np.array(atomwise_resids, dtype=int) atomwise_segids = np.array(atomwise_segids, dtype=object) - _update_topology_by_ids(self, - atomwise_resids=atomwise_resids, - atomwise_segids=atomwise_segids) + _update_topology_by_ids( + self, atomwise_resids=atomwise_resids, atomwise_segids=atomwise_segids + ) _generate_from_topology(self) @@ -1989,9 +2081,8 @@ def Merge(*args): # Create a new topology using the intersection of topology attributes blank_topology_attrs = set(dir(Topology(attrs=[]))) - common_attrs = set.intersection(*[set(dir(ag.universe._topology)) - for ag in args]) - tops = set(['bonds', 'angles', 'dihedrals', 'impropers']) + common_attrs = set.intersection(*[set(dir(ag.universe._topology)) for ag in args]) + tops = set(["bonds", "angles", "dihedrals", "impropers"]) attrs = [] @@ -2011,13 +2102,17 @@ def Merge(*args): elif issubclass(attr_class, SegmentAttr): attr = getattr(ag.segments, attrname) else: - raise NotImplementedError("Don't know how to handle" - " TopologyAttr not subclassed" - " from AtomAttr, ResidueAttr," - " or SegmentAttr.") + raise NotImplementedError( + "Don't know how to handle" + " TopologyAttr not subclassed" + " from AtomAttr, ResidueAttr," + " or SegmentAttr." + ) if type(attr) != np.ndarray: - raise TypeError('Encountered unexpected topology ' - 'attribute of type {}'.format(type(attr))) + raise TypeError( + "Encountered unexpected topology " + "attribute of type {}".format(type(attr)) + ) try: attr_array.extend(attr) except NameError: @@ -2027,7 +2122,7 @@ def Merge(*args): # Build up topology groups including only those that all arguments' # universes have - for t in (tops & common_attrs): + for t in tops & common_attrs: offset = 0 bondidx = [] types = [] @@ -2045,14 +2140,14 @@ def Merge(*args): # Map them so they refer to our new indices new_idx = [tuple([mapping[x] for x in entry]) for entry in tg.indices] bondidx.extend(new_idx) - if hasattr(tg, '_bondtypes'): + if hasattr(tg, "_bondtypes"): types.extend(tg._bondtypes) else: - types.extend([None]*len(tg)) + types.extend([None] * len(tg)) if any(t is None for t in types): attrs.append(bonds_class(bondidx)) else: - types = np.array(types, dtype='|S8') + types = np.array(types, dtype="|S8") attrs.append(bonds_class(bondidx, types)) # Renumber residue and segment indices @@ -2063,10 +2158,12 @@ def Merge(*args): seg_offset = 0 for ag in args: # create a mapping scheme for this atomgroup's parents - res_mapping = {r.resindex: i for i, r in enumerate(ag.residues, - start=res_offset)} - seg_mapping = {r.segindex: i for i, r in enumerate(ag.segments, - start=seg_offset)} + res_mapping = { + r.resindex: i for i, r in enumerate(ag.residues, start=res_offset) + } + seg_mapping = { + r.segindex: i for i, r in enumerate(ag.segments, start=seg_offset) + } res_offset += len(ag.residues) seg_offset += len(ag.segments) @@ -2082,19 +2179,24 @@ def Merge(*args): n_residues = len(set(residx)) n_segments = len(set(segidx)) - top = Topology(n_atoms, n_residues, n_segments, - attrs=attrs, - atom_resindex=residx, - residue_segindex=segidx) + top = Topology( + n_atoms, + n_residues, + n_segments, + attrs=attrs, + atom_resindex=residx, + residue_segindex=segidx, + ) # Create and populate a universe try: - #Create universe with coordinates if they exists in args + # Create universe with coordinates if they exists in args coords = np.vstack([a.positions for a in args]) - u = Universe(top, coords[None, :, :], - format=MDAnalysis.coordinates.memory.MemoryReader) + u = Universe( + top, coords[None, :, :], format=MDAnalysis.coordinates.memory.MemoryReader + ) except AttributeError: - #Create universe without coordinates if they dont exists in args + # Create universe without coordinates if they dont exists in args u = Universe(top) return u diff --git a/package/MDAnalysis/due.py b/package/MDAnalysis/due.py index 7ab1e8b55a..4d6f52e7d5 100644 --- a/package/MDAnalysis/due.py +++ b/package/MDAnalysis/due.py @@ -65,9 +65,7 @@ def _donothing_func(*args, **kwargs): from duecredit import due, BibTeX, Doi, Url if "due" in locals() and not hasattr(due, "cite"): - raise RuntimeError( - "Imported due lacks .cite. DueCredit is now disabled" - ) + raise RuntimeError("Imported due lacks .cite. DueCredit is now disabled") except Exception as err: if not isinstance(err, ImportError): import logging diff --git a/package/MDAnalysis/guesser/base.py b/package/MDAnalysis/guesser/base.py index c7bcc21e82..bfd7168b4a 100644 --- a/package/MDAnalysis/guesser/base.py +++ b/package/MDAnalysis/guesser/base.py @@ -142,8 +142,7 @@ def guess_attr(self, attr_to_guess, force_guess=False): top_attr = _TOPOLOGY_ATTRS[attr_to_guess] except KeyError: raise KeyError( - f"{attr_to_guess} is not a recognized MDAnalysis " - "topology attribute" + f"{attr_to_guess} is not a recognized MDAnalysis " "topology attribute" ) # make attribute to guess plural attr_to_guess = top_attr.attrname @@ -164,9 +163,7 @@ def guess_attr(self, attr_to_guess, force_guess=False): # check if the topology already has the attribute to partially guess it if hasattr(self._universe.atoms, attr_to_guess) and not force_guess: - attr_values = np.array( - getattr(self._universe.atoms, attr_to_guess, None) - ) + attr_values = np.array(getattr(self._universe.atoms, attr_to_guess, None)) empty_values = top_attr.are_values_missing(attr_values) diff --git a/package/MDAnalysis/guesser/default_guesser.py b/package/MDAnalysis/guesser/default_guesser.py index 2ecc64c1e6..a0deeb0245 100644 --- a/package/MDAnalysis/guesser/default_guesser.py +++ b/package/MDAnalysis/guesser/default_guesser.py @@ -438,9 +438,7 @@ def guess_bonds(self, atoms=None, coords=None): raise ValueError( ( "vdw radii for types: " - + ", ".join( - [t for t in set(atomtypes) if t not in vdwradii] - ) + + ", ".join([t for t in set(atomtypes) if t not in vdwradii]) + ". These can be defined manually using the" + f" keyword 'vdwradii'" ) @@ -464,9 +462,7 @@ def guess_bonds(self, atoms=None, coords=None): coords, max_cutoff=2.0 * max_vdw, min_cutoff=lower_bound, box=box ) for idx, (i, j) in enumerate(pairs): - d = ( - vdwradii[atomtypes[i]] + vdwradii[atomtypes[j]] - ) * fudge_factor + d = (vdwradii[atomtypes[i]] + vdwradii[atomtypes[j]]) * fudge_factor if dist[idx] < d: bonds.append((atoms[i].index, atoms[j].index)) return tuple(bonds) @@ -516,9 +512,7 @@ def guess_angles(self, bonds=None): for other_b in atom.bonds: if other_b != b: # if not the same bond I start as third_a = other_b.partner(atom) - desc = tuple( - [other_a.index, atom.index, third_a.index] - ) + desc = tuple([other_a.index, atom.index, third_a.index]) # first index always less than last if desc[0] > desc[-1]: desc = desc[::-1] @@ -569,9 +563,7 @@ def guess_dihedrals(self, angles=None): a_tup = tuple([a.index for a in b]) # angle as tuple of numbers # if searching with b[0], want tuple of (b[2], b[1], b[0], +new) # search the first and last atom of each angle - for atom, prefix in zip( - [b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup] - ): + for atom, prefix in zip([b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup]): for other_b in atom.bonds: if not other_b.partner(atom) in b: third_a = other_b.partner(atom) @@ -679,9 +671,6 @@ def guess_gasteiger_charges(self, atomgroup): ComputeGasteigerCharges(mol, throwOnParamFailure=True) return np.array( - [ - atom.GetDoubleProp("_GasteigerCharge") - for atom in mol.GetAtoms() - ], + [atom.GetDoubleProp("_GasteigerCharge") for atom in mol.GetAtoms()], dtype=np.float32, ) diff --git a/package/MDAnalysis/lib/NeighborSearch.py b/package/MDAnalysis/lib/NeighborSearch.py index b1f5fa7185..d8b6d60d90 100644 --- a/package/MDAnalysis/lib/NeighborSearch.py +++ b/package/MDAnalysis/lib/NeighborSearch.py @@ -136,6 +136,4 @@ def _index2level( elif level == "S": return atomgroup.segments else: - raise NotImplementedError( - "{0}: level not implemented".format(level) - ) + raise NotImplementedError("{0}: level not implemented".format(level)) diff --git a/package/MDAnalysis/lib/_distopia.py b/package/MDAnalysis/lib/_distopia.py index a6ec059168..20b814e099 100644 --- a/package/MDAnalysis/lib/_distopia.py +++ b/package/MDAnalysis/lib/_distopia.py @@ -121,9 +121,7 @@ def calc_dihedral( coords4: np.ndarray, results: np.ndarray, ) -> None: - distopia.dihedrals_no_box( - coords1, coords2, coords3, coords4, results=results - ) + distopia.dihedrals_no_box(coords1, coords2, coords3, coords4, results=results) def calc_dihedral_ortho( diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index b3f862e005..5084d53464 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -161,9 +161,7 @@ import importlib _distances = {} -_distances["serial"] = importlib.import_module( - ".c_distances", package="MDAnalysis.lib" -) +_distances["serial"] = importlib.import_module(".c_distances", package="MDAnalysis.lib") try: _distances["openmp"] = importlib.import_module( ".c_distances_openmp", package="MDAnalysis.lib" @@ -226,9 +224,7 @@ def _run( from .c_distances_openmp import OPENMP_ENABLED as USED_OPENMP -def _check_result_array( - result: Optional[npt.NDArray], shape: tuple -) -> npt.NDArray: +def _check_result_array(result: Optional[npt.NDArray], shape: tuple) -> npt.NDArray: """Check if the result array is ok to use. The `result` array must meet the following requirements: @@ -712,12 +708,8 @@ def _determine_method( return methods["nsgrid"] else: if box is None: - min_dim = np.array( - [reference.min(axis=0), configuration.min(axis=0)] - ) - max_dim = np.array( - [reference.max(axis=0), configuration.max(axis=0)] - ) + min_dim = np.array([reference.min(axis=0), configuration.min(axis=0)]) + max_dim = np.array([reference.max(axis=0), configuration.max(axis=0)]) size = max_dim.max(axis=0) - min_dim.min(axis=0) elif np.all(box[3:] == 90.0): size = box[:3] @@ -814,13 +806,9 @@ def _bruteforce_capped( distances = np.empty((0,), dtype=np.float64) if len(reference) > 0 and len(configuration) > 0: - _distances = distance_array( - reference, configuration, box=box, backend=backend - ) + _distances = distance_array(reference, configuration, box=box, backend=backend) if min_cutoff is not None: - mask = np.where( - (_distances <= max_cutoff) & (_distances > min_cutoff) - ) + mask = np.where((_distances <= max_cutoff) & (_distances > min_cutoff)) else: mask = np.where((_distances <= max_cutoff)) if mask[0].size > 0: @@ -1044,9 +1032,7 @@ def _nsgrid_capped( # Extra padding near the origin shiftref -= lmin - 0.1 * max_cutoff shiftconf -= lmin - 0.1 * max_cutoff - gridsearch = FastNS( - max_cutoff, shiftconf, box=pseudobox, pbc=False - ) + gridsearch = FastNS(max_cutoff, shiftconf, box=pseudobox, pbc=False) results = gridsearch.search(shiftref) else: gridsearch = FastNS(max_cutoff, configuration, box=box) diff --git a/package/MDAnalysis/lib/mdamath.py b/package/MDAnalysis/lib/mdamath.py index cef449c8f2..7e55becb50 100644 --- a/package/MDAnalysis/lib/mdamath.py +++ b/package/MDAnalysis/lib/mdamath.py @@ -163,9 +163,7 @@ def angle(a: npt.ArrayLike, b: npt.ArrayLike) -> float: return np.arccos(x) -def stp( - vec1: npt.ArrayLike, vec2: npt.ArrayLike, vec3: npt.ArrayLike -) -> float: +def stp(vec1: npt.ArrayLike, vec2: npt.ArrayLike, vec3: npt.ArrayLike) -> float: r"""Takes the scalar triple product of three vectors. Returns the volume *V* of the parallel epiped spanned by the three @@ -251,9 +249,7 @@ def sarrus_det(matrix: npt.NDArray) -> Union[float, npt.NDArray]: return _sarrus_det_multiple(m.reshape((-1, 3, 3))).reshape(shape[:-2]) -def triclinic_box( - x: npt.ArrayLike, y: npt.ArrayLike, z: npt.ArrayLike -) -> npt.NDArray: +def triclinic_box(x: npt.ArrayLike, y: npt.ArrayLike, z: npt.ArrayLike) -> npt.NDArray: """Convert the three triclinic box vectors to ``[lx, ly, lz, alpha, beta, gamma]``. @@ -368,9 +364,7 @@ def triclinic_vectors( dim = np.asarray(dimensions, dtype=np.float64) lx, ly, lz, alpha, beta, gamma = dim # Only positive edge lengths and angles in (0, 180) are allowed: - if not ( - np.all(dim > 0.0) and alpha < 180.0 and beta < 180.0 and gamma < 180.0 - ): + if not (np.all(dim > 0.0) and alpha < 180.0 and beta < 180.0 and gamma < 180.0): # invalid box, return zero vectors: box_matrix = np.zeros((3, 3), dtype=dtype) # detect orthogonal boxes: diff --git a/package/MDAnalysis/lib/picklable_file_io.py b/package/MDAnalysis/lib/picklable_file_io.py index f8050b14e5..b86e4de03d 100644 --- a/package/MDAnalysis/lib/picklable_file_io.py +++ b/package/MDAnalysis/lib/picklable_file_io.py @@ -460,9 +460,7 @@ def pickle_open(name, mode="rt"): .. versionadded:: 2.0.0 """ if mode not in {"r", "rt", "rb"}: - raise ValueError( - "Only read mode ('r', 'rt', 'rb') " "files can be pickled." - ) + raise ValueError("Only read mode ('r', 'rt', 'rb') " "files can be pickled.") name = os.fspath(name) raw = FileIOPicklable(name) if mode == "rb": @@ -533,9 +531,7 @@ def bz2_pickle_open(name, mode="rb"): .. versionadded:: 2.0.0 """ if mode not in {"r", "rt", "rb"}: - raise ValueError( - "Only read mode ('r', 'rt', 'rb') " "files can be pickled." - ) + raise ValueError("Only read mode ('r', 'rt', 'rb') " "files can be pickled.") bz_mode = mode.replace("t", "") binary_file = BZ2Picklable(name, bz_mode) if "t" in mode: @@ -606,9 +602,7 @@ def gzip_pickle_open(name, mode="rb"): .. versionadded:: 2.0.0 """ if mode not in {"r", "rt", "rb"}: - raise ValueError( - "Only read mode ('r', 'rt', 'rb') " "files can be pickled." - ) + raise ValueError("Only read mode ('r', 'rt', 'rb') " "files can be pickled.") gz_mode = mode.replace("t", "") binary_file = GzipPicklable(name, gz_mode) if "t" in mode: diff --git a/package/MDAnalysis/lib/pkdtree.py b/package/MDAnalysis/lib/pkdtree.py index 952b4672e3..b125a7a478 100644 --- a/package/MDAnalysis/lib/pkdtree.py +++ b/package/MDAnalysis/lib/pkdtree.py @@ -62,9 +62,7 @@ class PeriodicKDTree(object): """ - def __init__( - self, box: Optional[npt.ArrayLike] = None, leafsize: int = 10 - ) -> None: + def __init__(self, box: Optional[npt.ArrayLike] = None, leafsize: int = 10) -> None: """ Parameters @@ -98,9 +96,7 @@ def pbc(self): """ return self.box is not None - def set_coords( - self, coords: npt.ArrayLike, cutoff: Optional[float] = None - ) -> None: + def set_coords(self, coords: npt.ArrayLike, cutoff: Optional[float] = None) -> None: """Constructs KDTree from the coordinates Wrapping of coordinates to the primary unit cell is enforced @@ -147,9 +143,7 @@ def set_coords( # Bring the coordinates in the central cell self.coords = apply_PBC(coords, self.box) # generate duplicate images - self.aug, self.mapping = augment_coordinates( - self.coords, self.box, cutoff - ) + self.aug, self.mapping = augment_coordinates(self.coords, self.box, cutoff) # Images + coords self.all_coords = np.concatenate([self.coords, self.aug]) self.ckdt = cKDTree(self.all_coords, leafsize=self.leafsize) @@ -157,8 +151,7 @@ def set_coords( # if cutoff distance is provided for non PBC calculations if cutoff is not None: raise RuntimeError( - "Donot provide cutoff distance for" - " non PBC aware calculations" + "Donot provide cutoff distance for" " non PBC aware calculations" ) self.coords = coords self.ckdt = cKDTree(self.coords, self.leafsize) @@ -189,13 +182,9 @@ def search(self, centers: npt.ArrayLike, radius: float) -> npt.NDArray: # Sanity check if self.pbc: if self.cutoff is None: - raise ValueError( - "Cutoff needs to be provided when working with PBC." - ) + raise ValueError("Cutoff needs to be provided when working with PBC.") if self.cutoff < radius: - raise RuntimeError( - "Set cutoff greater or equal to the radius." - ) + raise RuntimeError("Set cutoff greater or equal to the radius.") # Bring all query points to the central cell wrapped_centers = apply_PBC(centers, self.box) indices = list(self.ckdt.query_ball_point(wrapped_centers, radius)) @@ -243,23 +232,15 @@ def search_pairs(self, radius: float) -> npt.NDArray: if self.pbc: if self.cutoff is None: - raise ValueError( - "Cutoff needs to be provided when working with PBC." - ) + raise ValueError("Cutoff needs to be provided when working with PBC.") if self.cutoff < radius: - raise RuntimeError( - "Set cutoff greater or equal to the radius." - ) + raise RuntimeError("Set cutoff greater or equal to the radius.") pairs = np.array(list(self.ckdt.query_pairs(radius)), dtype=np.intp) if self.pbc: if len(pairs) > 1: - pairs[:, 0] = undo_augment( - pairs[:, 0], self.mapping, len(self.coords) - ) - pairs[:, 1] = undo_augment( - pairs[:, 1], self.mapping, len(self.coords) - ) + pairs[:, 0] = undo_augment(pairs[:, 0], self.mapping, len(self.coords)) + pairs[:, 1] = undo_augment(pairs[:, 1], self.mapping, len(self.coords)) if pairs.size > 0: # First sort the pairs then pick the unique pairs pairs = np.sort(pairs, axis=1) @@ -307,13 +288,9 @@ class initialization # Sanity check if self.pbc: if self.cutoff is None: - raise ValueError( - "Cutoff needs to be provided when working with PBC." - ) + raise ValueError("Cutoff needs to be provided when working with PBC.") if self.cutoff < radius: - raise RuntimeError( - "Set cutoff greater or equal to the radius." - ) + raise RuntimeError("Set cutoff greater or equal to the radius.") # Bring all query points to the central cell wrapped_centers = apply_PBC(centers, self.box) other_tree = cKDTree(wrapped_centers, leafsize=self.leafsize) @@ -323,9 +300,7 @@ class initialization dtype=np.intp, ) if pairs.size > 0: - pairs[:, 1] = undo_augment( - pairs[:, 1], self.mapping, len(self.coords) - ) + pairs[:, 1] = undo_augment(pairs[:, 1], self.mapping, len(self.coords)) else: other_tree = cKDTree(centers, leafsize=self.leafsize) pairs = other_tree.query_ball_tree(self.ckdt, radius) diff --git a/package/MDAnalysis/lib/transformations.py b/package/MDAnalysis/lib/transformations.py index 27e5f01db9..627f09db76 100644 --- a/package/MDAnalysis/lib/transformations.py +++ b/package/MDAnalysis/lib/transformations.py @@ -377,17 +377,11 @@ def rotation_from_matrix(matrix): # rotation angle depending on direction cosa = (np.trace(R33) - 1.0) / 2.0 if abs(direction[2]) > 1e-8: - sina = ( - R[1, 0] + (cosa - 1.0) * direction[0] * direction[1] - ) / direction[2] + sina = (R[1, 0] + (cosa - 1.0) * direction[0] * direction[1]) / direction[2] elif abs(direction[1]) > 1e-8: - sina = ( - R[0, 2] + (cosa - 1.0) * direction[0] * direction[2] - ) / direction[1] + sina = (R[0, 2] + (cosa - 1.0) * direction[0] * direction[2]) / direction[1] else: - sina = ( - R[2, 1] + (cosa - 1.0) * direction[1] * direction[2] - ) / direction[0] + sina = (R[2, 1] + (cosa - 1.0) * direction[1] * direction[2]) / direction[0] angle = math.atan2(sina, cosa) return angle, direction, point @@ -482,9 +476,7 @@ def scale_from_matrix(matrix): return factor, origin, direction -def projection_matrix( - point, normal, direction=None, perspective=None, pseudo=False -): +def projection_matrix(point, normal, direction=None, perspective=None, pseudo=False): """Return matrix to project onto plane defined by point and normal. Using either perspective point, projection direction, or none of both. @@ -536,9 +528,7 @@ def projection_matrix( M[3, 3] = np.dot(perspective, normal) elif direction is not None: # parallel projection - direction = np.array( - direction[:3], dtype=np.float64, copy=no_copy_shim - ) + direction = np.array(direction[:3], dtype=np.float64, copy=no_copy_shim) scale = np.dot(direction, normal) M[:3, :3] -= np.outer(direction, normal) / scale M[:3, 3] = direction * (np.dot(point, normal) / scale) @@ -614,9 +604,7 @@ def projection_from_matrix(matrix, pseudo=False): # perspective projection i = np.where(abs(np.real(l)) > 1e-8)[0] if not len(i): - raise ValueError( - "no eigenvector not corresponding to eigenvalue 0" - ) + raise ValueError("no eigenvector not corresponding to eigenvalue 0") point = np.real(V[:, i[-1]]).squeeze() point /= point[3] normal = -M[3, :3] @@ -742,9 +730,7 @@ def shear_from_matrix(matrix): l, V = np.linalg.eig(M33) i = np.where(abs(np.real(l) - 1.0) < 1e-4)[0] if len(i) < 2: - raise ValueError( - "no two linear independent eigenvectors found {0!s}".format(l) - ) + raise ValueError("no two linear independent eigenvectors found {0!s}".format(l)) V = np.real(V[:, i]).squeeze().T lenorm = -1.0 for i0, i1 in ((0, 1), (0, 2), (1, 2)): diff --git a/package/MDAnalysis/lib/util.py b/package/MDAnalysis/lib/util.py index d227763d9e..3148def31b 100644 --- a/package/MDAnalysis/lib/util.py +++ b/package/MDAnalysis/lib/util.py @@ -411,14 +411,10 @@ def anyopen(datasource, mode="rt", reset=True): if stream is None: raise IOError( errno.EIO, - "Cannot open file or stream in mode={mode!r}.".format( - **vars() - ), + "Cannot open file or stream in mode={mode!r}.".format(**vars()), repr(filename), ) - elif mode.startswith("w") or mode.startswith( - "a" - ): # append 'a' not tested... + elif mode.startswith("w") or mode.startswith("a"): # append 'a' not tested... if isstream(datasource): stream = datasource try: @@ -438,9 +434,7 @@ def anyopen(datasource, mode="rt", reset=True): if stream is None: raise IOError( errno.EIO, - "Cannot open file or stream in mode={mode!r}.".format( - **vars() - ), + "Cannot open file or stream in mode={mode!r}.".format(**vars()), repr(filename), ) else: @@ -705,9 +699,7 @@ def __init__(self, stream, filename, reset=True, close=False): # on __del__ and super on python 3. Let's warn the user and ensure the # class works normally. if isinstance(stream, NamedStream): - warnings.warn( - "Constructed NamedStream from a NamedStream", RuntimeWarning - ) + warnings.warn("Constructed NamedStream from a NamedStream", RuntimeWarning) stream = stream.stream self.stream = stream self.name = filename @@ -959,9 +951,7 @@ def realpath(*args): """ if None in args: return None - return os.path.realpath( - os.path.expanduser(os.path.expandvars(os.path.join(*args))) - ) + return os.path.realpath(os.path.expanduser(os.path.expandvars(os.path.join(*args)))) def get_ext(filename): @@ -1179,10 +1169,7 @@ def read(self, line): try: return self.convertor(line[self.start : self.stop]) except ValueError: - errmsg = ( - f"{self}: Failed to read&convert " - f"{line[self.start:self.stop]}" - ) + errmsg = f"{self}: Failed to read&convert " f"{line[self.start:self.stop]}" raise ValueError(errmsg) from None def __len__(self): @@ -1233,18 +1220,14 @@ def __init__(self, fmt): """ self.fmt = fmt.split(",") - descriptors = [ - self.parse_FORTRAN_format(descriptor) for descriptor in self.fmt - ] + descriptors = [self.parse_FORTRAN_format(descriptor) for descriptor in self.fmt] start = 0 self.entries = [] for d in descriptors: if d["format"] != "X": for x in range(d["repeat"]): stop = start + d["length"] - self.entries.append( - FixedcolumnEntry(start, stop, d["format"]) - ) + self.entries.append(FixedcolumnEntry(start, stop, d["format"])) start = stop else: start += d["totallength"] @@ -1315,9 +1298,7 @@ def parse_FORTRAN_format(self, edit_descriptor): m = _FORTRAN_format_pattern.match(edit_descriptor.upper()) if m is None: try: - m = _FORTRAN_format_pattern.match( - "1" + edit_descriptor.upper() - ) + m = _FORTRAN_format_pattern.match("1" + edit_descriptor.upper()) if m is None: raise ValueError # really no idea what the descriptor is supposed to mean except: @@ -1480,9 +1461,7 @@ def get_weights(atoms, weights): } #: translation table for 1-letter codes --> *canonical* 3-letter codes. #: The table is used for :func:`convert_aa_code`. -amino_acid_codes = { - one: three for three, one in canonical_inverse_aa_codes.items() -} +amino_acid_codes = {one: three for three, one in canonical_inverse_aa_codes.items()} #: non-default charge state amino acids or special charge state descriptions #: (Not fully synchronized with :class:`MDAnalysis.core.selection.ProteinSelection`.) # fmt: off @@ -1757,9 +1736,7 @@ def unique_rows(arr, return_index=False): ) return u.view(arr.dtype).reshape(-1, m), r_idx else: - u = np.unique( - arr.view(dtype=np.dtype([(str(i), arr.dtype) for i in range(m)])) - ) + u = np.unique(arr.view(dtype=np.dtype([(str(i), arr.dtype) for i in range(m)]))) return u.view(arr.dtype).reshape(-1, m) @@ -2026,9 +2003,7 @@ def wrapper(group, *args, **kwargs): if group.isunique or warn_if_not_unique.warned: return groupmethod(group, *args, **kwargs) # Otherwise, throw a DuplicateWarning and execute the method. - method_name = ".".join( - (group.__class__.__name__, groupmethod.__name__) - ) + method_name = ".".join((group.__class__.__name__, groupmethod.__name__)) # Try to get the group's variable name(s): caller_locals = inspect.currentframe().f_back.f_locals.items() group_names = [] @@ -2045,9 +2020,8 @@ def wrapper(group, *args, **kwargs): else: group_name = " a.k.a. ".join(sorted(group_names)) group_repr = repr(group) - msg = ( - "{}(): {} {} contains duplicates. Results might be biased!" - "".format(method_name, group_name, group_repr) + msg = "{}(): {} {} contains duplicates. Results might be biased!" "".format( + method_name, group_name, group_repr ) warnings.warn(message=msg, category=DuplicateWarning, stacklevel=2) warn_if_not_unique.warned = True @@ -2183,14 +2157,11 @@ def check_coords(*coord_names, **options): allow_single = options.get("allow_single", True) convert_single = options.get("convert_single", True) reduce_result_if_single = options.get("reduce_result_if_single", True) - check_lengths_match = options.get( - "check_lengths_match", len(coord_names) > 1 - ) + check_lengths_match = options.get("check_lengths_match", len(coord_names) > 1) allow_atomgroup = options.get("allow_atomgroup", False) if not coord_names: raise ValueError( - "Decorator check_coords() cannot be used without " - "positional arguments." + "Decorator check_coords() cannot be used without " "positional arguments." ) def check_coords_decorator(func): @@ -2236,9 +2207,7 @@ def _check_coords(coords, argname): raise ValueError(errmsg) if enforce_dtype: try: - coords = coords.astype( - np.float32, order="C", copy=enforce_copy - ) + coords = coords.astype(np.float32, order="C", copy=enforce_copy) except ValueError: errmsg = ( f"{fname}(): {argname}.dtype must be" @@ -2298,15 +2267,11 @@ def wrapper(*args, **kwargs): for name in coord_names: idx = posargnames.index(name) if idx < len(args): - args[idx], is_single, ncoord = _check_coords( - args[idx], name - ) + args[idx], is_single, ncoord = _check_coords(args[idx], name) all_single &= is_single ncoords.append(ncoord) else: - kwargs[name], is_single, ncoord = _check_coords( - kwargs[name], name - ) + kwargs[name], is_single, ncoord = _check_coords(kwargs[name], name) all_single &= is_single ncoords.append(ncoord) if check_lengths_match and ncoords: @@ -2394,8 +2359,7 @@ def __init__( self.new_name = new_name if release is None: raise ValueError( - "deprecate: provide release in which " - "feature was deprecated." + "deprecate: provide release in which " "feature was deprecated." ) self.release = str(release) self.remove = str(remove) if remove is not None else remove diff --git a/package/MDAnalysis/selections/base.py b/package/MDAnalysis/selections/base.py index d9b49e516d..4b1db414b1 100644 --- a/package/MDAnalysis/selections/base.py +++ b/package/MDAnalysis/selections/base.py @@ -108,9 +108,7 @@ class SelectionWriterBase(metaclass=_Selectionmeta): commentfmt = None default_numterms = 8 - def __init__( - self, filename, mode="w", numterms=None, preamble=None, **kwargs - ): + def __init__(self, filename, mode="w", numterms=None, preamble=None, **kwargs): """Set up for writing to *filename*. Parameters @@ -130,9 +128,7 @@ def __init__( """ self.filename = util.filename(filename, ext=self.ext) if not mode in ("a", "w"): - raise ValueError( - "mode must be one of 'w', 'a', not {0!r}".format(mode) - ) + raise ValueError("mode must be one of 'w', 'a', not {0!r}".format(mode)) self.mode = mode self._current_mode = mode[0] if numterms is None or numterms < 0: @@ -212,9 +208,7 @@ def write(self, selection, number=None, name=None, frame=None, mode=None): out.write(" ".join(line)) if len(line) == step and not iatom + step == len(selection.atoms): out.write(" " + self.continuation + "\n") - out.write( - " " - ) # safe so that we don't have to put a space at the start of tail + out.write(" ") # safe so that we don't have to put a space at the start of tail self._write_tail(out) out.write("\n") # always terminate with newline diff --git a/package/MDAnalysis/selections/charmm.py b/package/MDAnalysis/selections/charmm.py index 62bbbd0497..c481f9afb0 100644 --- a/package/MDAnalysis/selections/charmm.py +++ b/package/MDAnalysis/selections/charmm.py @@ -47,9 +47,7 @@ class SelectionWriter(base.SelectionWriterBase): ext = "str" continuation = "-" commentfmt = "! %s" - default_numterms = ( - 4 # be conservative because CHARMM only reads 72 columns - ) + default_numterms = 4 # be conservative because CHARMM only reads 72 columns def _translate(self, atoms, **kwargs): # CHARMM index is 1-based @@ -60,11 +58,7 @@ def _index(atom): def _write_head(self, out, **kwargs): out.write(self.comment("MDAnalysis CHARMM selection")) - out.write( - "DEFINE {name!s} SELECT ".format(**kwargs) - + self.continuation - + "\n" - ) + out.write("DEFINE {name!s} SELECT ".format(**kwargs) + self.continuation + "\n") def _write_tail(self, out, **kwargs): out.write("END") diff --git a/package/MDAnalysis/selections/pymol.py b/package/MDAnalysis/selections/pymol.py index d528a1394b..f61171c2fb 100644 --- a/package/MDAnalysis/selections/pymol.py +++ b/package/MDAnalysis/selections/pymol.py @@ -59,6 +59,4 @@ def _index(atom): def _write_head(self, out, **kwargs): out.write(self.comment("MDAnalysis PyMol selection")) - out.write( - "select {name!s}, ".format(**kwargs) + self.continuation + "\n" - ) + out.write("select {name!s}, ".format(**kwargs) + self.continuation + "\n") diff --git a/package/MDAnalysis/topology/CRDParser.py b/package/MDAnalysis/topology/CRDParser.py index c0322824ba..84a944d4bd 100644 --- a/package/MDAnalysis/topology/CRDParser.py +++ b/package/MDAnalysis/topology/CRDParser.py @@ -103,9 +103,7 @@ def parse(self, **kwargs): ---- Could use the resnum and temp factor better """ - extformat = FORTRANReader( - "2I10,2X,A8,2X,A8,3F20.10,2X,A8,2X,A8,F20.10" - ) + extformat = FORTRANReader("2I10,2X,A8,2X,A8,3F20.10,2X,A8,2X,A8,F20.10") stdformat = FORTRANReader("2I5,1X,A4,1X,A4,3F10.5,1X,A4,1X,A4,F10.5") atomids = [] @@ -124,10 +122,7 @@ def parse(self, **kwargs): elif line.split()[-1] == "EXT" and int(line.split()[0]): r = extformat continue - elif ( - line.split()[0] == line.split()[-1] - and line.split()[0] != "*" - ): + elif line.split()[0] == line.split()[-1] and line.split()[0] != "*": r = stdformat continue # anything else should be an atom @@ -146,8 +141,7 @@ def parse(self, **kwargs): ) = r.read(line) except Exception: errmsg = ( - f"Check CRD format at line {linenum + 1}: " - f"{line.rstrip()}" + f"Check CRD format at line {linenum + 1}: " f"{line.rstrip()}" ) raise ValueError(errmsg) from None @@ -169,9 +163,7 @@ def parse(self, **kwargs): segids = np.array(segids, dtype=object) atom_residx, (res_resids, res_resnames, res_resnums, res_segids) = ( - change_squash( - (resids, resnames), (resids, resnames, resnums, segids) - ) + change_squash((resids, resnames), (resids, resnames, resnums, segids)) ) res_segidx, (seg_segids,) = change_squash((res_segids,), (res_segids,)) diff --git a/package/MDAnalysis/topology/DMSParser.py b/package/MDAnalysis/topology/DMSParser.py index 691b47eed6..3f3d988ac2 100644 --- a/package/MDAnalysis/topology/DMSParser.py +++ b/package/MDAnalysis/topology/DMSParser.py @@ -201,9 +201,7 @@ def dict_factory(cursor, row): topattrs.append(Resnames(res_resnames)) if any(res_segids) and not any(val is None for val in res_segids): - res_segidx, (res_segids,) = change_squash( - (res_segids,), (res_segids,) - ) + res_segidx, (res_segids,) = change_squash((res_segids,), (res_segids,)) uniq_seg = np.unique(res_segids) idx2seg = {idx: res_segids[idx] for idx in res_segidx} diff --git a/package/MDAnalysis/topology/GMSParser.py b/package/MDAnalysis/topology/GMSParser.py index 41e85f73ec..41e55f4677 100644 --- a/package/MDAnalysis/topology/GMSParser.py +++ b/package/MDAnalysis/topology/GMSParser.py @@ -100,9 +100,7 @@ def parse(self, **kwargs): line = inf.readline() if not line: raise EOFError - if re.match( - r"^\s+ATOM\s+ATOMIC\s+COORDINATES\s*\(BOHR\).*", line - ): + if re.match(r"^\s+ATOM\s+ATOMIC\s+COORDINATES\s*\(BOHR\).*", line): break line = inf.readline() # skip diff --git a/package/MDAnalysis/topology/GSDParser.py b/package/MDAnalysis/topology/GSDParser.py index 45f7e570b0..86ff832270 100644 --- a/package/MDAnalysis/topology/GSDParser.py +++ b/package/MDAnalysis/topology/GSDParser.py @@ -139,9 +139,7 @@ def parse(self, **kwargs): # set radii, masses, charges p = snap.particles - attrs["diameter"] = Radii( - np.array(p.diameter / 2.0, dtype=np.float32) - ) + attrs["diameter"] = Radii(np.array(p.diameter / 2.0, dtype=np.float32)) attrs["mass"] = Masses(np.array(p.mass, dtype=np.float64)) attrs["charge"] = Charges(np.array(p.charge, dtype=np.float32)) diff --git a/package/MDAnalysis/topology/ITPParser.py b/package/MDAnalysis/topology/ITPParser.py index 1aa87b3864..6952db1aea 100644 --- a/package/MDAnalysis/topology/ITPParser.py +++ b/package/MDAnalysis/topology/ITPParser.py @@ -368,9 +368,7 @@ def parse_dihedrals(self, line): funct_values=(1, 3, 5, 8, 9, 10, 11), ) if not dih: - self.add_param( - line, self.impropers, n_funct=4, funct_values=(2, 4) - ) + self.add_param(line, self.impropers, n_funct=4, funct_values=(2, 4)) def parse_constraints(self, line): self.add_param(line, self.bonds, n_funct=2, funct_values=(1, 2)) @@ -407,9 +405,7 @@ def resolve_residue_attrs(self): self.resolved_residue_attrs = True - def shift_indices( - self, atomid=0, resid=0, molnum=0, cgnr=0, n_res=0, n_atoms=0 - ): + def shift_indices(self, atomid=0, resid=0, molnum=0, cgnr=0, n_res=0, n_atoms=0): """ Get attributes ready for adding onto a larger topology. @@ -577,9 +573,7 @@ def parse( self.parser = self.parse_molecules elif self.current_mol: - self.parser = self.current_mol.parsers.get( - section, self._pass - ) + self.parser = self.current_mol.parsers.get(section, self._pass) else: self.parser = self._pass @@ -599,22 +593,14 @@ def parse( if not all(self.charges): empty = self.charges == "" self.charges[empty] = [ - ( - self.atomtypes.get(x)["charge"] - if x in self.atomtypes.keys() - else "" - ) + (self.atomtypes.get(x)["charge"] if x in self.atomtypes.keys() else "") for x in self.types[empty] ] if not all(self.masses): empty = self.masses == "" self.masses[empty] = [ - ( - self.atomtypes.get(x)["mass"] - if x in self.atomtypes.keys() - else "" - ) + (self.atomtypes.get(x)["mass"] if x in self.atomtypes.keys() else "") for x in self.types[empty] ] @@ -634,15 +620,11 @@ def parse( empty = self.masses == "" self.masses[empty] = Masses.missing_value_label - attrs.append( - Masses(np.array(self.masses, dtype=np.float64), guessed=False) - ) + attrs.append(Masses(np.array(self.masses, dtype=np.float64), guessed=False)) self.elements = DefaultGuesser(None).guess_types(self.types) if all(e.capitalize() in SYMB2Z for e in self.elements): - attrs.append( - Elements(np.array(self.elements, dtype=object), guessed=True) - ) + attrs.append(Elements(np.array(self.elements, dtype=object), guessed=True)) warnings.warn( "The elements attribute has been populated by guessing " "elements from atom types. This behaviour has been " diff --git a/package/MDAnalysis/topology/LAMMPSParser.py b/package/MDAnalysis/topology/LAMMPSParser.py index 61404fbbe7..cb5d4f07b5 100644 --- a/package/MDAnalysis/topology/LAMMPSParser.py +++ b/package/MDAnalysis/topology/LAMMPSParser.py @@ -229,9 +229,7 @@ def grab_datafile(self): header[token] = line.split(token)[0] continue - sects = { - f[l]: f[l + 1 : starts[i + 1]] for i, l in enumerate(starts[:-1]) - } + sects = {f[l]: f[l + 1 : starts[i + 1]] for i, l in enumerate(starts[:-1])} return header, sects @@ -317,9 +315,7 @@ def parse(self, **kwargs): (Impropers, "Impropers", 4), ]: try: - type, sect = self._parse_bond_section( - sects[L], nentries, mapping - ) + type, sect = self._parse_bond_section(sects[L], nentries, mapping) except KeyError: type, sect = [], [] @@ -327,9 +323,7 @@ def parse(self, **kwargs): return top - def read_DATA_timestep( - self, n_atoms, TS_class, TS_kwargs, atom_style=None - ): + def read_DATA_timestep(self, n_atoms, TS_class, TS_kwargs, atom_style=None): """Read a DATA file and try and extract x, v, box. - positions @@ -362,9 +356,7 @@ def read_DATA_timestep( else: velocities = None - ts = TS_class.from_coordinates( - positions, velocities=velocities, **TS_kwargs - ) + ts = TS_class.from_coordinates(positions, velocities=velocities, **TS_kwargs) ts.dimensions = unitcell return ts @@ -451,9 +443,7 @@ def _parse_bond_section(self, datalines, nentries, mapping): for line in datalines: line = line.split() # map to 0 based int - section.append( - tuple([mapping[int(x)] for x in line[2 : 2 + nentries]]) - ) + section.append(tuple([mapping[int(x)] for x in line[2 : 2 + nentries]])) type.append(line[1]) return tuple(type), tuple(section) @@ -554,9 +544,7 @@ def _parse_atoms(self, datalines, massdict=None): attrs.append(Resnums(resids.copy())) attrs.append(Segids(np.array(["SYSTEM"], dtype=object))) - top = Topology( - n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx - ) + top = Topology(n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx) return top @@ -729,9 +717,7 @@ def parse(self, **kwargs): attrs.append(DUMP_HEADERS[key]["attr_class"](value[order])) attrs.append(Segids(np.array(["SYSTEM"], dtype=object))) - return Topology( - natoms, n_residues, 1, attrs=attrs, atom_resindex=residx - ) + return Topology(natoms, n_residues, 1, attrs=attrs, atom_resindex=residx) @functools.total_ordering diff --git a/package/MDAnalysis/topology/MMTFParser.py b/package/MDAnalysis/topology/MMTFParser.py index 38711115bc..c2b5aa0a1a 100644 --- a/package/MDAnalysis/topology/MMTFParser.py +++ b/package/MDAnalysis/topology/MMTFParser.py @@ -204,12 +204,7 @@ def iter_atoms(field): attrs.append(Atomids(np.arange(natoms), guessed=True)) if mtop.alt_loc_list: attrs.append( - AltLocs( - [ - val.replace("\x00", "").strip() - for val in mtop.alt_loc_list - ] - ) + AltLocs([val.replace("\x00", "").strip() for val in mtop.alt_loc_list]) ) else: attrs.append(AltLocs([""] * natoms)) @@ -234,12 +229,7 @@ def iter_atoms(field): # mmtf empty icode is '\x00' rather than '' if mtop.ins_code_list: attrs.append( - ICodes( - [ - val.replace("\x00", "").strip() - for val in mtop.ins_code_list - ] - ) + ICodes([val.replace("\x00", "").strip() for val in mtop.ins_code_list]) ) else: attrs.append(ICodes([""] * nresidues)) @@ -286,9 +276,7 @@ def iter_atoms(field): offset += groupID_2_natoms[gtype] # add inter group bonds if not mtop.bond_atom_list is None: # optional field - for x, y in zip( - mtop.bond_atom_list[1::2], mtop.bond_atom_list[::2] - ): + for x, y in zip(mtop.bond_atom_list[1::2], mtop.bond_atom_list[::2]): if x > y: x, y = y, x bonds.append((x, y)) diff --git a/package/MDAnalysis/topology/MOL2Parser.py b/package/MDAnalysis/topology/MOL2Parser.py index 114633c0c4..488a143816 100644 --- a/package/MDAnalysis/topology/MOL2Parser.py +++ b/package/MDAnalysis/topology/MOL2Parser.py @@ -197,9 +197,7 @@ def parse(self, **kwargs): for a in atom_lines: columns = a.split() if len(columns) >= 9: - aid, name, x, y, z, atom_type, resid, resname, charge = ( - columns[:9] - ) + aid, name, x, y, z, atom_type, resid, resname, charge = columns[:9] elif len(columns) < 6: raise ValueError( f"The @ATOM block in mol2 file" @@ -305,8 +303,6 @@ def parse(self, **kwargs): bonds.append(bond) attrs.append(Bonds(bonds, order=bondorder)) - top = Topology( - n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx - ) + top = Topology(n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx) return top diff --git a/package/MDAnalysis/topology/PDBParser.py b/package/MDAnalysis/topology/PDBParser.py index b168b0a67a..9fcb19a51a 100644 --- a/package/MDAnalysis/topology/PDBParser.py +++ b/package/MDAnalysis/topology/PDBParser.py @@ -149,16 +149,22 @@ def hy36decode(width, s): int Base-10 integer corresponding to hybrid36. """ - if (len(s) == width): + if len(s) == width: f = s[0] - if (f == "-" or f == " " or f.isdigit()): + if f == "-" or f == " " or f.isdigit(): return int(s) - elif (f in DIGITS_UPPER_VALUES): - return decode_pure(digits_values=DIGITS_UPPER_VALUES, - s=s) - 10 * 36 ** (width - 1) + 10 ** width - elif (f in DIGITS_LOWER_VALUES): - return decode_pure(digits_values=DIGITS_LOWER_VALUES, - s=s) + 16 * 36 ** (width - 1) + 10 ** width + elif f in DIGITS_UPPER_VALUES: + return ( + decode_pure(digits_values=DIGITS_UPPER_VALUES, s=s) + - 10 * 36 ** (width - 1) + + 10**width + ) + elif f in DIGITS_LOWER_VALUES: + return ( + decode_pure(digits_values=DIGITS_LOWER_VALUES, s=s) + + 16 * 36 ** (width - 1) + + 10**width + ) raise ValueError("invalid number literal.") @@ -217,7 +223,8 @@ class PDBParser(TopologyReaderBase): be generated if the segids is not present or if the chainids are not completely equal to segids. """ - format = ['PDB', 'ENT'] + + format = ["PDB", "ENT"] def parse(self, **kwargs): """Parse atom information from PDB file @@ -231,11 +238,11 @@ def parse(self, **kwargs): try: bonds = self._parsebonds(top.ids.values) except AttributeError: - warnings.warn("Invalid atom serials were present, " - "bonds will not be parsed") + warnings.warn( + "Invalid atom serials were present, " "bonds will not be parsed" + ) except RuntimeError: - warnings.warn("CONECT records was corrupt, " - "bonds will not be parsed") + warnings.warn("CONECT records was corrupt, " "bonds will not be parsed") else: # Issue 2832: don't append Bonds if there are no bonds if bonds: @@ -268,9 +275,9 @@ def _parseatoms(self, **kwargs): line = line.strip() # Remove extra spaces if not line: # Skip line if empty continue - if line.startswith('END'): + if line.startswith("END"): break - if not line.startswith(('ATOM', 'HETATM')): + if not line.startswith(("ATOM", "HETATM")): continue record_types.append(line[:6].strip()) @@ -306,8 +313,9 @@ def _parseatoms(self, **kwargs): resid += 10000 resid_prev = resid except ValueError: - warnings.warn("PDB file is missing resid information. " - "Defaulted to '1'") + warnings.warn( + "PDB file is missing resid information. " "Defaulted to '1'" + ) resid = 1 finally: resids.append(resid) @@ -320,8 +328,9 @@ def _parseatoms(self, **kwargs): # Warn about wrapped serials if self._wrapped_serials: - warnings.warn("Serial numbers went over 100,000. " - "Higher serials have been guessed") + warnings.warn( + "Serial numbers went over 100,000. " "Higher serials have been guessed" + ) # If segids is not equal to chainids, warn the user if any([a != b for a, b in zip(segids, chainids)]): @@ -329,14 +338,17 @@ def _parseatoms(self, **kwargs): # If segids not present, try to use chainids if not any(segids): - logger.info("Setting segids from chainIDs because no segids " - "found in the PDB file.") + logger.info( + "Setting segids from chainIDs because no segids " + "found in the PDB file." + ) segids = chainids # If force_chainids_to_segids is set, use chainids as segids if kwargs.get("force_chainids_to_segids", False): - logger.info("force_chainids_to_segids is set. " - "Using chain IDs as segment IDs.") + logger.info( + "force_chainids_to_segids is set. " "Using chain IDs as segment IDs." + ) segids = chainids n_atoms = len(serials) @@ -344,13 +356,13 @@ def _parseatoms(self, **kwargs): attrs = [] # Make Atom TopologyAttrs for vals, Attr, dtype in ( - (names, Atomnames, object), - (altlocs, AltLocs, object), - (chainids, ChainIDs, object), - (record_types, RecordTypes, object), - (serials, Atomids, np.int32), - (tempfactors, Tempfactors, np.float32), - (occupancies, Occupancies, np.float32), + (names, Atomnames, object), + (altlocs, AltLocs, object), + (chainids, ChainIDs, object), + (record_types, RecordTypes, object), + (serials, Atomids, np.int32), + (tempfactors, Tempfactors, np.float32), + (occupancies, Occupancies, np.float32), ): attrs.append(Attr(np.array(vals, dtype=dtype))) # OPT: We do this check twice, maybe could refactor to avoid this @@ -364,41 +376,47 @@ def _parseatoms(self, **kwargs): if elem.capitalize() in SYMB2Z: validated_elements.append(elem.capitalize()) else: - wmsg = (f"Unknown element {elem} found for some atoms. " - f"These have been given an empty element record. " - f"If needed they can be guessed using " - f"universe.guess_TopologyAttrs(context='default'," - " to_guess=['elements']).") + wmsg = ( + f"Unknown element {elem} found for some atoms. " + f"These have been given an empty element record. " + f"If needed they can be guessed using " + f"universe.guess_TopologyAttrs(context='default'," + " to_guess=['elements'])." + ) warnings.warn(wmsg) - validated_elements.append('') + validated_elements.append("") attrs.append(Elements(np.array(validated_elements, dtype=object))) else: - warnings.warn("Element information is missing, elements attribute " - "will not be populated. If needed these can be" - " guessed using universe.guess_TopologyAttrs(" - "context='default', to_guess=['elements']).") + warnings.warn( + "Element information is missing, elements attribute " + "will not be populated. If needed these can be" + " guessed using universe.guess_TopologyAttrs(" + "context='default', to_guess=['elements'])." + ) if any(formalcharges): try: for i, entry in enumerate(formalcharges): - if not entry == '': - if entry == '0': + if not entry == "": + if entry == "0": # Technically a lack of charge shouldn't be in the # PDB but MDA has a few files that specifically # have 0 entries, indicating that some folks # interpret 0 as an allowed entry formalcharges[i] = 0 - elif ('+' in entry) or ('-' in entry): + elif ("+" in entry) or ("-" in entry): formalcharges[i] = int(entry[::-1]) else: raise ValueError else: formalcharges[i] = 0 except ValueError: - wmsg = (f"Unknown entry {entry} encountered in formal charge " - "field. This likely indicates that the PDB file is " - "not fully standard compliant. The formalcharges " - "attribute will not be populated.") + wmsg = ( + f"Unknown entry {entry} encountered in formal charge " + "field. This likely indicates that the PDB file is " + "not fully standard compliant. The formalcharges " + "attribute will not be populated." + ) warnings.warn(wmsg) else: attrs.append(FormalCharges(np.array(formalcharges, dtype=int))) @@ -406,38 +424,45 @@ def _parseatoms(self, **kwargs): # Residue level stuff from here resids = np.array(resids, dtype=np.int32) resnames = np.array(resnames, dtype=object) - if self.format == 'XPDB': # XPDB doesn't have icodes - icodes = [''] * n_atoms + if self.format == "XPDB": # XPDB doesn't have icodes + icodes = [""] * n_atoms icodes = np.array(icodes, dtype=object) resnums = resids.copy() segids = np.array(segids, dtype=object) residx, (resids, resnames, icodes, resnums, segids) = change_squash( - (resids, resnames, icodes, segids), (resids, resnames, icodes, resnums, segids)) + (resids, resnames, icodes, segids), + (resids, resnames, icodes, resnums, segids), + ) n_residues = len(resids) attrs.append(Resnums(resnums)) attrs.append(Resids(resids)) attrs.append(ICodes(icodes)) attrs.append(Resnames(resnames)) - if ( - kwargs.get("force_chainids_to_segids", False) or - (any(segids) and not any(val is None for val in segids)) + if kwargs.get("force_chainids_to_segids", False) or ( + any(segids) and not any(val is None for val in segids) ): segidx, (segids,) = change_squash((segids,), (segids,)) n_segments = len(segids) attrs.append(Segids(segids)) else: n_segments = 1 - attrs.append(Segids(np.array(['SYSTEM'], dtype=object))) + attrs.append(Segids(np.array(["SYSTEM"], dtype=object))) segidx = None - logger.info("Segment/chain ID is empty, " - "setting segids to default value 'SYSTEM'.") - - top = Topology(n_atoms, n_residues, n_segments, - attrs=attrs, - atom_resindex=residx, - residue_segindex=segidx) + logger.info( + "Segment/chain ID is empty, " + "setting segids to default value 'SYSTEM'." + ) + + top = Topology( + n_atoms, + n_residues, + n_segments, + attrs=attrs, + atom_resindex=residx, + residue_segindex=segidx, + ) return top @@ -450,8 +475,9 @@ def _parsebonds(self, serials): # If the serials wrapped, this won't work if self._wrapped_serials: - warnings.warn("Invalid atom serials were present, bonds will not" - " be parsed") + warnings.warn( + "Invalid atom serials were present, bonds will not" " be parsed" + ) raise AttributeError # gets caught in parse # Mapping between the atom array indicies a.index and atom ids @@ -471,7 +497,8 @@ def _parsebonds(self, serials): # Ignore these as they are not real atoms warnings.warn( "PDB file contained CONECT record to TER entry. " - "These are not included in bonds.") + "These are not included in bonds." + ) else: bonds.add(bond) @@ -505,13 +532,14 @@ def _parse_conect(conect): try: if len(conect[11:]) % n_bond_atoms != 0: - raise RuntimeError("Bond atoms aren't aligned proberly for CONECT " - "record: {}".format(conect)) + raise RuntimeError( + "Bond atoms aren't aligned proberly for CONECT " + "record: {}".format(conect) + ) except ZeroDivisionError: # Conect record with only one entry (CONECT A\n) warnings.warn("Found CONECT record with single entry, ignoring this") return atom_id, [] # return empty list to allow iteration over nothing - bond_atoms = (int(conect[11 + i * 5: 16 + i * 5]) for i in - range(n_bond_atoms)) + bond_atoms = (int(conect[11 + i * 5 : 16 + i * 5]) for i in range(n_bond_atoms)) return atom_id, bond_atoms diff --git a/package/MDAnalysis/topology/PSFParser.py b/package/MDAnalysis/topology/PSFParser.py index 531c2ae592..2101366c90 100644 --- a/package/MDAnalysis/topology/PSFParser.py +++ b/package/MDAnalysis/topology/PSFParser.py @@ -132,8 +132,7 @@ def parse(self, **kwargs): for _ in range(int(title[0])): next(psffile) logger.debug( - "PSF file {0}: format {1}" - "".format(self.filename, self._format) + "PSF file {0}: format {1}" "".format(self.filename, self._format) ) # Atoms first and mandatory @@ -178,9 +177,7 @@ def _parse_sec(self, psffile, section_info): sect_type = header[1].strip("!:") # Make sure the section type matches the desc if not sect_type == desc: - err = "Expected section {0} but found {1}" "".format( - desc, sect_type - ) + err = "Expected section {0} but found {1}" "".format(desc, sect_type) logger.error(err) raise ValueError(err) # Now figure out how many lines to read @@ -319,8 +316,7 @@ def _parseatoms(self, lines, atoms_per, numlines): " continuing with fingers crossed!" ) logger.debug( - "First NAMD-type line: {0}: {1}" - "".format(i, line.rstrip()) + "First NAMD-type line: {0}: {1}" "".format(i, line.rstrip()) ) atomids[i] = vals[0] diff --git a/package/MDAnalysis/topology/TOPParser.py b/package/MDAnalysis/topology/TOPParser.py index ba61bea0b0..7f90e18464 100644 --- a/package/MDAnalysis/topology/TOPParser.py +++ b/package/MDAnalysis/topology/TOPParser.py @@ -256,9 +256,9 @@ def parse(self, **kwargs): while next_section is not None: try: - (num_per_record, per_line, func, name, sect_num) = ( - sections[next_section] - ) + (num_per_record, per_line, func, name, sect_num) = sections[ + next_section + ] except KeyError: def next_getter(): @@ -305,12 +305,7 @@ def next_getter(): # Deal with recreating bonds and angle records here attrs["bonds"] = Bonds( - [ - i - for i in itertools.chain( - attrs.pop("bonda"), attrs.pop("bondh") - ) - ] + [i for i in itertools.chain(attrs.pop("bonda"), attrs.pop("bondh"))] ) attrs["angles"] = Angles( @@ -349,9 +344,7 @@ def next_getter(): # Amber's 'RESIDUE_CHAINID' is a by-residue attribute, turn it into # a by-atom attribute when present. See PR #4007. if "segids" in attrs and len(attrs["segids"]) == n_res: - segidx, (segids,) = change_squash( - (attrs["segids"],), (attrs["segids"],) - ) + segidx, (segids,) = change_squash((attrs["segids"],), (attrs["segids"],)) chainids = [attrs["segids"][r] for r in residx] attrs["segids"] = Segids(segids) @@ -594,8 +587,7 @@ def parse_chunks(self, data, chunksize): into chunks of size num_per_record, and only extract the atom ids. """ vals = [ - tuple(data[x : x + chunksize - 1]) - for x in range(0, len(data), chunksize) + tuple(data[x : x + chunksize - 1]) for x in range(0, len(data), chunksize) ] return vals diff --git a/package/MDAnalysis/topology/TPRParser.py b/package/MDAnalysis/topology/TPRParser.py index 5fd29d1985..08ced830fb 100644 --- a/package/MDAnalysis/topology/TPRParser.py +++ b/package/MDAnalysis/topology/TPRParser.py @@ -242,9 +242,7 @@ def parse(self, tpr_resid_from_one=True, **kwargs): if state_ngtc > 0: if th.fver < 69: # redundancy due to different versions tpr_utils.ndo_real(data, state_ngtc) - tpr_utils.ndo_real( - data, state_ngtc - ) # relevant to Berendsen tcoupl_lambda + tpr_utils.ndo_real(data, state_ngtc) # relevant to Berendsen tcoupl_lambda if th.bTop: tpr_top = tpr_utils.do_mtop( diff --git a/package/MDAnalysis/topology/__init__.py b/package/MDAnalysis/topology/__init__.py index 945deaf436..5adc807adc 100644 --- a/package/MDAnalysis/topology/__init__.py +++ b/package/MDAnalysis/topology/__init__.py @@ -311,10 +311,24 @@ """ -__all__ = ['core', 'PSFParser', 'PDBParser', 'PQRParser', 'GROParser', - 'CRDParser', 'TOPParser', 'PDBQTParser', 'TPRParser', - 'LAMMPSParser', 'XYZParser', 'GMSParser', 'DLPolyParser', - 'HoomdXMLParser','GSDParser', 'ITPParser'] +__all__ = [ + "core", + "PSFParser", + "PDBParser", + "PQRParser", + "GROParser", + "CRDParser", + "TOPParser", + "PDBQTParser", + "TPRParser", + "LAMMPSParser", + "XYZParser", + "GMSParser", + "DLPolyParser", + "HoomdXMLParser", + "GSDParser", + "ITPParser", +] from . import core from . import PSFParser diff --git a/package/MDAnalysis/topology/base.py b/package/MDAnalysis/topology/base.py index f4ae0894e4..7462845e5a 100644 --- a/package/MDAnalysis/topology/base.py +++ b/package/MDAnalysis/topology/base.py @@ -77,10 +77,11 @@ class ThingParser(TopologyReaderBase): .. versionchanged:: 1.0.0 Added format_hint functionality """ + def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - fmt = util.asiterable(classdict['format']) + fmt = util.asiterable(classdict["format"]) except KeyError: pass else: @@ -88,8 +89,9 @@ def __init__(cls, name, bases, classdict): fmt_name = fmt_name.upper() _PARSERS[fmt_name] = cls - if '_format_hint' in classdict: - _PARSER_HINTS[fmt_name] = classdict['_format_hint'].__func__ + if "_format_hint" in classdict: + _PARSER_HINTS[fmt_name] = classdict["_format_hint"].__func__ + class TopologyReaderBase(IOBase, metaclass=_Topologymeta): """Base class for topology readers @@ -114,6 +116,7 @@ class TopologyReaderBase(IOBase, metaclass=_Topologymeta): .. versionchanged:: 0.9.2 Added keyword 'universe' to pass to Atom creation. """ + def __init__(self, filename): self.filename = filename @@ -137,7 +140,8 @@ def squash_by(child_parent_ids, *attributes): *parent_attrs - len(parent) of the other attributes """ unique_resids, sort_mask, atom_idx = np.unique( - child_parent_ids, return_index=True, return_inverse=True) + child_parent_ids, return_index=True, return_inverse=True + ) return atom_idx, unique_resids, [attr[sort_mask] for attr in attributes] @@ -176,16 +180,15 @@ def change_squash(criteria, to_squash): new_resnames: ['RsA', 'RsB', 'RsC'] new_segids: ['A', 'A', 'B'] """ + def get_borders(*arrays): """Generator of indices to slice arrays when they change""" - borders = np.nonzero(reduce(np.logical_or, - (a[:-1] != a[1:] for a in arrays))) + borders = np.nonzero(reduce(np.logical_or, (a[:-1] != a[1:] for a in arrays))) # Add Nones so we can slice from start to end return [None] + list(borders[0] + 1) + [None] l0 = len(criteria[0]) - if not all(len(other) == l0 - for other in itertools.chain(criteria[1:], to_squash)): + if not all(len(other) == l0 for other in itertools.chain(criteria[1:], to_squash)): raise ValueError("All arrays must be equally sized") # 1) Detect where resids change diff --git a/package/MDAnalysis/topology/guessers.py b/package/MDAnalysis/topology/guessers.py index 6ae316cd02..383346f684 100644 --- a/package/MDAnalysis/topology/guessers.py +++ b/package/MDAnalysis/topology/guessers.py @@ -180,9 +180,7 @@ def guess_types(atom_names): ------- atom_types : np.ndarray dtype object """ - return np.array( - [guess_atom_element(name) for name in atom_names], dtype=object - ) + return np.array([guess_atom_element(name) for name in atom_names], dtype=object) @deprecate(release="2.8.0", remove="3.0.0", message=deprecation_msg) @@ -426,9 +424,7 @@ def guess_dihedrals(angles): a_tup = tuple([a.index for a in b]) # angle as tuple of numbers # if searching with b[0], want tuple of (b[2], b[1], b[0], +new) # search the first and last atom of each angle - for atom, prefix in zip( - [b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup] - ): + for atom, prefix in zip([b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup]): for other_b in atom.bonds: if not other_b.partner(atom) in b: third_a = other_b.partner(atom) diff --git a/package/MDAnalysis/topology/tpr/obj.py b/package/MDAnalysis/topology/tpr/obj.py index 93c5a83ee7..abb6ae6f88 100644 --- a/package/MDAnalysis/topology/tpr/obj.py +++ b/package/MDAnalysis/topology/tpr/obj.py @@ -139,9 +139,7 @@ def remap_impr(self, atom_start_ndx): class AtomKind(object): - def __init__( - self, id, name, type, resid, resname, mass, charge, atomic_number - ): + def __init__(self, id, name, type, resid, resname, mass, charge, atomic_number): # id is only within the scope of a single molecule, not the whole system self.id = id self.name = name diff --git a/package/MDAnalysis/topology/tpr/utils.py b/package/MDAnalysis/topology/tpr/utils.py index a332181392..83a1b6f32e 100644 --- a/package/MDAnalysis/topology/tpr/utils.py +++ b/package/MDAnalysis/topology/tpr/utils.py @@ -79,6 +79,7 @@ class TPXUnpacker(xdrlib.Unpacker): """ Extend the standard XDR unpacker for the specificity of TPX files. """ + def __init__(self, data): super().__init__(data) self._buf = self.get_buffer() @@ -103,10 +104,10 @@ def _unpack_value(self, item_size, struct_template): return struct.unpack(struct_template, content)[0] def unpack_int64(self): - return self._unpack_value(8, '>q') + return self._unpack_value(8, ">q") def unpack_uint64(self): - return self._unpack_value(8, '>Q') + return self._unpack_value(8, ">Q") def unpack_ushort(self): return self.unpack_uint() @@ -114,7 +115,7 @@ def unpack_ushort(self): def unpack_uchar(self): # TPX files prior to gromacs 2020 (tpx version < 119) use unsigned ints # (4 bytes) instead of unsigned chars. - return self._unpack_value(4, '>I') + return self._unpack_value(4, ">I") def do_string(self): """ @@ -138,11 +139,12 @@ class TPXUnpacker2020(TPXUnpacker): gromacs 2020, changes le meaning of some types in the file body (the header keep using the previous implementation of the serializer). """ + @classmethod def from_unpacker(cls, unpacker): new_unpacker = cls(unpacker.get_buffer()) new_unpacker._pos = unpacker.get_position() - if hasattr(unpacker, 'unpack_real'): + if hasattr(unpacker, "unpack_real"): if unpacker.unpack_real == unpacker.unpack_float: new_unpacker.unpack_real = new_unpacker.unpack_float elif unpacker.unpack_real == unpacker.unpack_double: @@ -153,7 +155,7 @@ def from_unpacker(cls, unpacker): def unpack_fstring(self, n): if n < 0: - raise ValueError('Size of fstring cannot be negative.') + raise ValueError("Size of fstring cannot be negative.") start_position = self._pos end_position = self._pos = start_position + n if end_position > len(self._buf): @@ -164,12 +166,12 @@ def unpack_fstring(self, n): def unpack_ushort(self): # The InMemorySerializer implements ushort according to the XDR standard # on the contrary to the IO serializer. - return self._unpack_value(2, '>H') + return self._unpack_value(2, ">H") def unpack_uchar(self): # The InMemorySerializer implements uchar according to the XDR standard # on the contrary to the IO serializer. - return self._unpack_value(1, '>B') + return self._unpack_value(1, ">B") def do_string(self): """ @@ -221,12 +223,11 @@ def define_unpack_real(prec, data): def read_tpxheader(data): - """this function is now compatible with do_tpxheader in tpxio.cpp - """ + """this function is now compatible with do_tpxheader in tpxio.cpp""" # Last compatibility check with gromacs-2016 ver_str = data.do_string() # version string e.g. VERSION 4.0.5 - if not ver_str.startswith(b'VERSION'): - raise ValueError('Input does not look like a TPR file.') + if not ver_str.startswith(b"VERSION"): + raise ValueError("Input does not look like a TPR file.") precision = data.unpack_int() # e.g. 4 define_unpack_real(precision, data) fileVersion = data.unpack_int() # version of tpx file @@ -239,7 +240,9 @@ def read_tpxheader(data): data.unpack_int() # the value is 8, but haven't found the file_tag = data.do_string() - fileGeneration = data.unpack_int() if fileVersion >= 26 else 0 # generation of tpx file, e.g. 17 + fileGeneration = ( + data.unpack_int() if fileVersion >= 26 else 0 + ) # generation of tpx file, e.g. 17 # Versions before 77 don't have the tag, set it to TPX_TAG_RELEASE file_tag # file_tag is used for comparing with tpx_tag. Only tpr files with a @@ -249,7 +252,9 @@ def read_tpxheader(data): file_tag = data.do_string() if fileVersion >= 81 else setting.TPX_TAG_RELEASE natoms = data.unpack_int() # total number of atoms - ngtc = data.unpack_int() if fileVersion >= 28 else 0 # number of groups for T-coupling + ngtc = ( + data.unpack_int() if fileVersion >= 28 else 0 + ) # number of groups for T-coupling if fileVersion < 62: # not sure what these two are for. @@ -272,9 +277,24 @@ def read_tpxheader(data): if fileVersion >= setting.tpxv_AddSizeField and fileGeneration >= 27: sizeOfTprBody = data.unpack_int64() - th = obj.TpxHeader(ver_str, precision, fileVersion, fileGeneration, - file_tag, natoms, ngtc, fep_state, lamb, - bIr, bTop, bX, bV, bF, bBox, sizeOfTprBody) + th = obj.TpxHeader( + ver_str, + precision, + fileVersion, + fileGeneration, + file_tag, + natoms, + ngtc, + fep_state, + lamb, + bIr, + bTop, + bX, + bV, + bF, + bBox, + sizeOfTprBody, + ) return th @@ -328,7 +348,7 @@ def do_mtop(data, fver, tpr_resid_from_one=False): mb = do_molblock(data) # segment is made to correspond to the molblock as in gromacs, the # naming is kind of arbitrary - molblock = mtop.moltypes[mb.molb_type].name.decode('utf-8') + molblock = mtop.moltypes[mb.molb_type].name.decode("utf-8") segid = f"seg_{i}_{molblock}" chainID = molblock[14:] if molblock[:14] == "Protein_chain_" else molblock for j in range(mb.molb_nmol): @@ -372,17 +392,9 @@ def do_mtop(data, fver, tpr_resid_from_one=False): resids += 1 resnames = np.array(resnames, dtype=object) - (residx, new_resids, - (new_resnames, - new_moltypes, - new_molnums, - perres_segids - ) - ) = squash_by(resids, - resnames, - moltypes, - molnums, - segids) + (residx, new_resids, (new_resnames, new_moltypes, new_molnums, perres_segids)) = ( + squash_by(resids, resnames, moltypes, molnums, segids) + ) residueids = Resids(new_resids) residuenames = Resnames(new_resnames) residue_moltypes = Moltypes(new_moltypes) @@ -414,10 +426,8 @@ def do_mtop(data, fver, tpr_resid_from_one=False): ) top.add_TopologyAttr(Bonds([bond for bond in bonds if bond])) top.add_TopologyAttr(Angles([angle for angle in angles if angle])) - top.add_TopologyAttr(Dihedrals([dihedral for dihedral in dihedrals - if dihedral])) - top.add_TopologyAttr(Impropers([improper for improper in impropers - if improper])) + top.add_TopologyAttr(Dihedrals([dihedral for dihedral in dihedrals if dihedral])) + top.add_TopologyAttr(Impropers([improper for improper in impropers if improper])) if any(elements): elements = Elements(np.array(elements, dtype=object)) @@ -473,9 +483,12 @@ def do_iparams(data, functypes, fver): # Not all elif cases in this function has been used and tested for k, i in enumerate(functypes): if i in [ - setting.F_ANGLES, setting.F_G96ANGLES, - setting.F_BONDS, setting.F_G96BONDS, - setting.F_HARMONIC, setting.F_IDIHS + setting.F_ANGLES, + setting.F_G96ANGLES, + setting.F_BONDS, + setting.F_G96BONDS, + setting.F_HARMONIC, + setting.F_IDIHS, ]: do_harm(data) elif i in [setting.F_RESTRANGLES]: @@ -503,8 +516,10 @@ def do_iparams(data, functypes, fver): data.unpack_real() # restraint.up2B data.unpack_real() # restraint.kB elif i in [ - setting.F_TABBONDS, setting.F_TABBONDSNC, - setting.F_TABANGLES, setting.F_TABDIHS, + setting.F_TABBONDS, + setting.F_TABBONDSNC, + setting.F_TABANGLES, + setting.F_TABDIHS, ]: data.unpack_real() # tab.kA data.unpack_int() # tab.table @@ -530,7 +545,7 @@ def do_iparams(data, functypes, fver): data.unpack_real() # u_b.kUBB elif i in [setting.F_QUARTIC_ANGLES]: data.unpack_real() # qangle.theta - ndo_real(data, 5) # qangle.c + ndo_real(data, 5) # qangle.c elif i in [setting.F_BHAM]: data.unpack_real() # bham.a data.unpack_real() # bham.b @@ -590,8 +605,10 @@ def do_iparams(data, functypes, fver): data.unpack_real() # ljcnb.c12 elif i in [ - setting.F_PIDIHS, setting.F_ANGRES, - setting.F_ANGRESZ, setting.F_PDIHS, + setting.F_PIDIHS, + setting.F_ANGRES, + setting.F_ANGRESZ, + setting.F_PDIHS, ]: data.unpack_real() # pdihs_phiA data.unpack_real() # pdihs_cpA @@ -640,8 +657,8 @@ def do_iparams(data, functypes, fver): do_rvec(data) # posres.fcB elif i in [setting.F_FBPOSRES]: - data.unpack_int() # fbposres.geom - do_rvec(data) # fbposres.pos0 + data.unpack_int() # fbposres.geom + do_rvec(data) # fbposres.pos0 data.unpack_real() # fbposres.r data.unpack_real() # fbposres.k @@ -720,16 +737,18 @@ def do_moltype(data, symtab, fver): #### start: MDAnalysis specific atomkinds = [] for k, a in enumerate(atoms_obj.atoms): - atomkinds.append(obj.AtomKind( - k, - atoms_obj.atomnames[k], - atoms_obj.type[k], - a.resind, - atoms_obj.resnames[a.resind], - a.m, - a.q, - a.atomnumber, - )) + atomkinds.append( + obj.AtomKind( + k, + atoms_obj.atomnames[k], + atoms_obj.type[k], + a.resind, + atoms_obj.resnames[a.resind], + a.m, + a.q, + a.atomnumber, + ) + ) #### end: MDAnalysis specific # key info: about bonds, angles, dih, improp dih. @@ -745,21 +764,44 @@ def do_moltype(data, symtab, fver): # the following if..elif..else statement needs to be updated as new # type of interactions become interested - if ik_obj.name in ['BONDS', 'G96BONDS', 'MORSE', 'CUBICBONDS', - 'CONNBONDS', 'HARMONIC', 'FENEBONDS', - 'RESTRAINTPOT', 'CONSTR', 'CONSTRNC', - 'TABBONDS', 'TABBONDSNC']: + if ik_obj.name in [ + "BONDS", + "G96BONDS", + "MORSE", + "CUBICBONDS", + "CONNBONDS", + "HARMONIC", + "FENEBONDS", + "RESTRAINTPOT", + "CONSTR", + "CONSTRNC", + "TABBONDS", + "TABBONDSNC", + ]: bonds += list(ik_obj.process(ias)) - elif ik_obj.name in ['ANGLES', 'G96ANGLES', 'CROSS_BOND_BOND', - 'CROSS_BOND_ANGLE', 'UREY_BRADLEY', 'QANGLES', - 'RESTRANGLES', 'TABANGLES']: + elif ik_obj.name in [ + "ANGLES", + "G96ANGLES", + "CROSS_BOND_BOND", + "CROSS_BOND_ANGLE", + "UREY_BRADLEY", + "QANGLES", + "RESTRANGLES", + "TABANGLES", + ]: angles += list(ik_obj.process(ias)) - elif ik_obj.name in ['PDIHS', 'RBDIHS', 'RESTRDIHS', 'CBTDIHS', - 'FOURDIHS', 'TABDIHS']: + elif ik_obj.name in [ + "PDIHS", + "RBDIHS", + "RESTRDIHS", + "CBTDIHS", + "FOURDIHS", + "TABDIHS", + ]: dihs += list(ik_obj.process(ias)) - elif ik_obj.name in ['IDIHS', 'PIDIHS']: + elif ik_obj.name in ["IDIHS", "PIDIHS"]: impr += list(ik_obj.process(ias)) - elif ik_obj.name == 'SETTLE': + elif ik_obj.name == "SETTLE": # SETTLE interactions are optimized triangular constraints for # water molecules. They should be counted as a pair of bonds # between the oxygen and the hydrogens. In older versions of @@ -866,8 +908,7 @@ def do_ilists(data, fver): iatoms.append(l_) return [ - obj.Ilist(n, it, i) - for n, it, i in zip(nr, setting.interaction_types, iatoms) + obj.Ilist(n, it, i) for n, it, i in zip(nr, setting.interaction_types, iatoms) ] @@ -882,8 +923,9 @@ def do_molblock(data): if molb_nposres_xB > 0: ndo_rvec(data, molb_nposres_xB) - return obj.Molblock(molb_type, molb_nmol, molb_natoms_mol, - molb_nposres_xA, molb_nposres_xB) + return obj.Molblock( + molb_type, molb_nmol, molb_natoms_mol, molb_nposres_xA, molb_nposres_xB + ) def do_block(data): diff --git a/package/MDAnalysis/transformations/boxdimensions.py b/package/MDAnalysis/transformations/boxdimensions.py index c18cdc36a7..750cd55392 100644 --- a/package/MDAnalysis/transformations/boxdimensions.py +++ b/package/MDAnalysis/transformations/boxdimensions.py @@ -87,9 +87,7 @@ class set_dimensions(TransformationBase): """ def __init__(self, dimensions, max_threads=None, parallelizable=True): - super().__init__( - max_threads=max_threads, parallelizable=parallelizable - ) + super().__init__(max_threads=max_threads, parallelizable=parallelizable) self.dimensions = dimensions try: diff --git a/package/MDAnalysis/transformations/fit.py b/package/MDAnalysis/transformations/fit.py index 89336128cb..81268b9a30 100644 --- a/package/MDAnalysis/transformations/fit.py +++ b/package/MDAnalysis/transformations/fit.py @@ -100,9 +100,7 @@ def __init__( max_threads=None, parallelizable=True, ): - super().__init__( - max_threads=max_threads, parallelizable=parallelizable - ) + super().__init__(max_threads=max_threads, parallelizable=parallelizable) self.ag = ag self.reference = reference @@ -114,9 +112,7 @@ def __init__( 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 = ( @@ -126,10 +122,7 @@ def __init__( raise ValueError(errmsg) except AttributeError: - errmsg = ( - f"{self.ag} or {self.reference} is not valid" - f"Universe/AtomGroup" - ) + errmsg = 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 @@ -138,9 +131,7 @@ def __init__( 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 @@ -219,9 +210,7 @@ def __init__( max_threads=1, parallelizable=True, ): - super().__init__( - max_threads=max_threads, parallelizable=parallelizable - ) + super().__init__(max_threads=max_threads, parallelizable=parallelizable) self.ag = ag self.reference = reference @@ -233,9 +222,7 @@ def __init__( 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 = ( @@ -245,8 +232,7 @@ def __init__( 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( @@ -266,13 +252,9 @@ def _transform(self, ts): 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 - ) + 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] diff --git a/package/MDAnalysis/transformations/nojump.py b/package/MDAnalysis/transformations/nojump.py index d4a54f6f8d..dfb2caa3c4 100644 --- a/package/MDAnalysis/transformations/nojump.py +++ b/package/MDAnalysis/transformations/nojump.py @@ -133,8 +133,7 @@ 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." @@ -156,9 +155,7 @@ 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 @@ -167,9 +164,7 @@ 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 d091dd9bbf..e15df72083 100644 --- a/package/MDAnalysis/transformations/positionaveraging.py +++ b/package/MDAnalysis/transformations/positionaveraging.py @@ -148,9 +148,7 @@ def __init__( max_threads=None, parallelizable=False, ): - super().__init__( - max_threads=max_threads, parallelizable=parallelizable - ) + super().__init__(max_threads=max_threads, parallelizable=parallelizable) self.avg_frames = avg_frames self.check_reset = check_reset self.current_avg = 0 diff --git a/package/MDAnalysis/transformations/rotate.py b/package/MDAnalysis/transformations/rotate.py index 4d8fa71d0b..d247a83dc9 100644 --- a/package/MDAnalysis/transformations/rotate.py +++ b/package/MDAnalysis/transformations/rotate.py @@ -134,9 +134,7 @@ def __init__( max_threads=1, parallelizable=True, ): - super().__init__( - max_threads=max_threads, parallelizable=parallelizable - ) + super().__init__(max_threads=max_threads, parallelizable=parallelizable) self.angle = angle self.direction = direction @@ -149,16 +147,12 @@ def __init__( 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) - ) + 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): @@ -170,14 +164,10 @@ def __init__( 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 " diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index c28fffd404..43f9bb10ef 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -72,9 +72,7 @@ class translate(TransformationBase): """ def __init__(self, vector, max_threads=None, parallelizable=True): - super().__init__( - max_threads=max_threads, parallelizable=parallelizable - ) + super().__init__(max_threads=max_threads, parallelizable=parallelizable) self.vector = vector @@ -141,9 +139,7 @@ def __init__( max_threads=None, parallelizable=True, ): - super().__init__( - max_threads=max_threads, parallelizable=parallelizable - ) + super().__init__(max_threads=max_threads, parallelizable=parallelizable) self.ag = ag self.center = center @@ -157,13 +153,9 @@ def __init__( 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 - ) + 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 - ) + self.center_method = partial(self.ag.center_of_mass, wrap=pbc_arg) else: raise ValueError(f"{self.center} is valid for center") except AttributeError: @@ -171,9 +163,7 @@ def __init__( 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 f8c1d8dbae..1605925932 100644 --- a/package/MDAnalysis/transformations/wrap.py +++ b/package/MDAnalysis/transformations/wrap.py @@ -91,12 +91,8 @@ class wrap(TransformationBase): 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 @@ -156,9 +152,7 @@ class unwrap(TransformationBase): """ 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/MDAnalysis/units.py b/package/MDAnalysis/units.py index 4f18652119..f123a02f2c 100644 --- a/package/MDAnalysis/units.py +++ b/package/MDAnalysis/units.py @@ -262,14 +262,12 @@ def __getitem__(self, key): "nm^{-3}": 1 / 1e-3, "nanometer^{-3}": 1 / 1e-3, "Molar": 1 / (1e-27 * constants["N_Avogadro"]), - "SPC": 1 - / (1e-24 * constants["N_Avogadro"] * water["SPC"] / water["MolarMass"]), + "SPC": 1 / (1e-24 * constants["N_Avogadro"] * water["SPC"] / water["MolarMass"]), "TIP3P": 1 / (1e-24 * constants["N_Avogadro"] * water["TIP3P"] / water["MolarMass"]), "TIP4P": 1 / (1e-24 * constants["N_Avogadro"] * water["TIP4P"] / water["MolarMass"]), - "water": 1 - / (1e-24 * constants["N_Avogadro"] * water["exp"] / water["MolarMass"]), + "water": 1 / (1e-24 * constants["N_Avogadro"] * water["exp"] / water["MolarMass"]), } diff --git a/package/MDAnalysis/visualization/streamlines.py b/package/MDAnalysis/visualization/streamlines.py index 12534a2e77..6248fdb042 100644 --- a/package/MDAnalysis/visualization/streamlines.py +++ b/package/MDAnalysis/visualization/streamlines.py @@ -166,9 +166,7 @@ def split_grid(grid, num_cores): list_square_vertex_arrays_per_core = np.array_split( list_all_squares_in_grid, num_cores ) - list_parent_index_values = np.array_split( - list_parent_index_values, num_cores - ) + list_parent_index_values = np.array_split(list_parent_index_values, num_cores) return [ list_square_vertex_arrays_per_core, list_parent_index_values, @@ -214,14 +212,16 @@ def _produce_list_centroids_this_frame( ): # if there are no particles of interest in this particular square list_centroids_this_frame.append(None) else: - current_coordinate_array_in_square = ( - relevant_particle_coordinate_array_xy[indices] - ) + current_coordinate_array_in_square = relevant_particle_coordinate_array_xy[ + indices + ] current_square_indices_centroid = np.average( current_coordinate_array_in_square, axis=0 ) list_centroids_this_frame.append(current_square_indices_centroid) - return list_centroids_this_frame # a list of numpy xy centroid arrays for this frame + return ( + list_centroids_this_frame # a list of numpy xy centroid arrays for this frame + ) def per_core_work( @@ -239,9 +239,7 @@ def per_core_work( The code to perform on a given core given the list of square vertices assigned to it. """ # obtain the relevant coordinates for particles of interest - universe_object = MDAnalysis.Universe( - topology_file_path, trajectory_file_path - ) + universe_object = MDAnalysis.Universe(topology_file_path, trajectory_file_path) list_previous_frame_centroids = [] list_previous_frame_indices = [] for ts in universe_object.trajectory: @@ -259,11 +257,9 @@ def per_core_work( ) ) # likewise, I will need a list of centroids of particles in each square (same order as above list): - list_centroids_in_squares_this_frame = ( - _produce_list_centroids_this_frame( - list_indices_in_squares_this_frame, - relevant_particle_coordinate_array_xy, - ) + list_centroids_in_squares_this_frame = _produce_list_centroids_this_frame( + list_indices_in_squares_this_frame, + relevant_particle_coordinate_array_xy, ) if ( list_previous_frame_indices @@ -285,9 +281,7 @@ def per_core_work( xy_deltas_to_write.append([0, 0]) else: xy_deltas_to_write.append( - np.subtract( - square_1_centroid, square_2_centroid - ).tolist() + np.subtract(square_1_centroid, square_2_centroid).tolist() ) # xy_deltas_to_write = np.subtract(np.array( @@ -303,15 +297,11 @@ def per_core_work( # with the xy and dx,dy values calculated I need to set the values from this frame to previous frame # values in anticipation of the next frame: - list_previous_frame_centroids = ( - list_centroids_in_squares_this_frame[:] - ) + list_previous_frame_centroids = list_centroids_in_squares_this_frame[:] list_previous_frame_indices = list_indices_in_squares_this_frame[:] else: # either no points in squares or after the first frame I'll just reset the 'previous' values so they # can be used when consecutive frames have proper values - list_previous_frame_centroids = ( - list_centroids_in_squares_this_frame[:] - ) + list_previous_frame_centroids = list_centroids_in_squares_this_frame[:] list_previous_frame_indices = list_indices_in_squares_this_frame[:] if ts.frame > end_frame: break # stop here @@ -427,9 +417,7 @@ def log_result_to_parent(delta_array): parent_list_deltas.extend(delta_array) tuple_of_limits = (xmin, xmax, ymin, ymax) - grid = produce_grid( - tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing - ) + grid = produce_grid(tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing) ( list_square_vertex_arrays_per_core, list_parent_index_values, diff --git a/package/MDAnalysis/visualization/streamlines_3D.py b/package/MDAnalysis/visualization/streamlines_3D.py index 4d2dace77b..5f00a288a7 100644 --- a/package/MDAnalysis/visualization/streamlines_3D.py +++ b/package/MDAnalysis/visualization/streamlines_3D.py @@ -56,9 +56,7 @@ import MDAnalysis -def determine_container_limits( - topology_file_path, trajectory_file_path, buffer_value -): +def determine_container_limits(topology_file_path, trajectory_file_path, buffer_value): """Calculate the extent of the atom coordinates + buffer. A function for the parent process which should take the input trajectory @@ -74,12 +72,8 @@ def determine_container_limits( buffer_value : float buffer value (padding) in +/- {x, y, z} """ - universe_object = MDAnalysis.Universe( - topology_file_path, trajectory_file_path - ) - all_atom_selection = universe_object.select_atoms( - "all" - ) # select all particles + universe_object = MDAnalysis.Universe(topology_file_path, trajectory_file_path) + all_atom_selection = universe_object.select_atoms("all") # select all particles all_atom_coordinate_array = all_atom_selection.positions x_min, x_max, y_min, y_max, z_min, z_max = [ all_atom_coordinate_array[..., 0].min(), @@ -164,21 +158,15 @@ def split_grid(grid, num_cores): x ): # each x_sheet should have shape (25,23) and the same x value in each element array_all_x_values_current_sheet = x_sheet.flatten() - ordered_list_per_sheet_x_values.append( - array_all_x_values_current_sheet - ) + ordered_list_per_sheet_x_values.append(array_all_x_values_current_sheet) ordered_list_per_sheet_y_values = [] for y_columns in y: array_all_y_values_current_sheet = y_columns.flatten() - ordered_list_per_sheet_y_values.append( - array_all_y_values_current_sheet - ) + ordered_list_per_sheet_y_values.append(array_all_y_values_current_sheet) ordered_list_per_sheet_z_values = [] for z_slices in z: array_all_z_values_current_sheet = z_slices.flatten() - ordered_list_per_sheet_z_values.append( - array_all_z_values_current_sheet - ) + ordered_list_per_sheet_z_values.append(array_all_z_values_current_sheet) ordered_list_cartesian_coordinates_per_sheet = [] for x_sheet_coords, y_sheet_coords, z_sheet_coords in zip( @@ -221,17 +209,11 @@ def split_grid(grid, num_cores): current_index : current_index + 2, ... ].tolist() next_two_vertices_base_sheet = current_base_sheet_array[ - current_index - + num_z_values : 2 - + num_z_values - + current_index, + current_index + num_z_values : 2 + num_z_values + current_index, ..., ].tolist() next_two_vertices_top_sheet = current_top_sheet_array[ - current_index - + num_z_values : 2 - + num_z_values - + current_index, + current_index + num_z_values : 2 + num_z_values + current_index, ..., ].tolist() for vertex_set in [ @@ -246,9 +228,7 @@ def split_grid(grid, num_cores): 8, 3, ), "vertex_array has incorrect shape" - cube_centroid = np.average( - np.array(current_list_cube_vertices), axis=0 - ) + cube_centroid = np.average(np.array(current_list_cube_vertices), axis=0) dictionary_cubes_centroids_indices[cube_counter] = { "centroid": cube_centroid, "vertex_list": current_list_cube_vertices, @@ -266,9 +246,7 @@ def split_grid(grid, num_cores): # produce an array of pseudo cube indices (actually the dictionary keys which are cube numbers in string format): pseudo_cube_indices = np.arange(0, total_cubes) - sublist_of_cube_indices_per_core = np.array_split( - pseudo_cube_indices, num_cores - ) + sublist_of_cube_indices_per_core = np.array_split(pseudo_cube_indices, num_cores) # now, the split of pseudoindices seems to work well, and the above sublist_of_cube_indices_per_core is a list of # arrays of cube numbers / keys in the original dictionary # now I think I'll try to produce a list of dictionaries that each contain their assigned cubes based on the above @@ -309,23 +287,16 @@ def per_core_work( list_previous_frame_indices = [] # define some utility functions for trajectory iteration: - def point_in_cube( - array_point_coordinates, list_cube_vertices, cube_centroid - ): + def point_in_cube(array_point_coordinates, list_cube_vertices, cube_centroid): """Determine if an array of coordinates are within a cube.""" # the simulation particle point can't be more than half the cube side length away from the cube centroid in # any given dimension: array_cube_vertices = np.array(list_cube_vertices) cube_half_side_length = ( - scipy.spatial.distance.pdist( - array_cube_vertices, "euclidean" - ).min() - / 2.0 + scipy.spatial.distance.pdist(array_cube_vertices, "euclidean").min() / 2.0 ) - array_cube_vertex_distances_from_centroid = ( - scipy.spatial.distance.cdist( - array_cube_vertices, cube_centroid[np.newaxis, :] - ) + array_cube_vertex_distances_from_centroid = scipy.spatial.distance.cdist( + array_cube_vertices, cube_centroid[np.newaxis, :] ) np.testing.assert_allclose( array_cube_vertex_distances_from_centroid.min(), @@ -380,9 +351,7 @@ def update_dictionary_point_in_cube_start_frame( array_simulation_particle_coordinates[index_list_in_cube], axis=0, ) - cube["centroid_of_particles_first_frame"] = ( - centroid_particles_in_cube - ) + cube["centroid_of_particles_first_frame"] = centroid_particles_in_cube else: # empty cube cube["centroid_of_particles_first_frame"] = None cube_counter += 1 @@ -427,9 +396,7 @@ def update_dictionary_end_frame( update_dictionary_point_in_cube_start_frame( start_frame_coord_array, dictionary_cube_data_this_core ) - update_dictionary_end_frame( - end_frame_coord_array, dictionary_cube_data_this_core - ) + update_dictionary_end_frame(end_frame_coord_array, dictionary_cube_data_this_core) return dictionary_cube_data_this_core @@ -448,9 +415,7 @@ def produce_coordinate_arrays_single_process( waste memory. """ - universe_object = MDAnalysis.Universe( - topology_file_path, trajectory_file_path - ) + universe_object = MDAnalysis.Universe(topology_file_path, trajectory_file_path) relevant_particles = universe_object.select_atoms(MDA_selection) # pull out coordinate arrays from desired frames: for ts in universe_object.trajectory: @@ -605,9 +570,7 @@ def log_result_to_parent(process_dict): tuple_of_limits = (xmin, xmax, ymin, ymax, zmin, zmax) # step 2: produce a suitable grid (will assume that grid size / container size does not vary during simulation--or # at least not beyond the buffer limit, such that this grid can be used for all subsequent frames) - grid = produce_grid( - tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing - ) + grid = produce_grid(tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing) # step 3: split the grid into a dictionary of cube information that can be sent to each core for processing: list_dictionaries_for_cores, total_cubes, num_sheets, delta_array_shape = ( split_grid(grid=grid, num_cores=num_cores) @@ -655,15 +618,15 @@ def log_result_to_parent(process_dict): z_index_current_column = 0 # column total_cubes_current_sheet = 0 for cube_number in range(0, total_cubes): - dx_array[ - current_sheet, y_index_current_sheet, z_index_current_column - ] = parent_cube_dictionary[cube_number]["dx"] - dy_array[ - current_sheet, y_index_current_sheet, z_index_current_column - ] = parent_cube_dictionary[cube_number]["dy"] - dz_array[ - current_sheet, y_index_current_sheet, z_index_current_column - ] = parent_cube_dictionary[cube_number]["dz"] + dx_array[current_sheet, y_index_current_sheet, z_index_current_column] = ( + parent_cube_dictionary[cube_number]["dx"] + ) + dy_array[current_sheet, y_index_current_sheet, z_index_current_column] = ( + parent_cube_dictionary[cube_number]["dy"] + ) + dz_array[current_sheet, y_index_current_sheet, z_index_current_column] = ( + parent_cube_dictionary[cube_number]["dz"] + ) z_index_current_column += 1 total_cubes_current_sheet += 1 if z_index_current_column == delta_array_shape[2]: diff --git a/package/doc/sphinx/source/conf.py b/package/doc/sphinx/source/conf.py index d1a288ed34..d7a6ce5700 100644 --- a/package/doc/sphinx/source/conf.py +++ b/package/doc/sphinx/source/conf.py @@ -176,9 +176,7 @@ class KeyStyle(UnsrtStyle): # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_context = { - "versions_json_url": "https://docs.mdanalysis.org/versions.json" -} +html_context = {"versions_json_url": "https://docs.mdanalysis.org/versions.json"} # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". diff --git a/package/setup.py b/package/setup.py index ff96377241..7f90d19c71 100755 --- a/package/setup.py +++ b/package/setup.py @@ -78,9 +78,7 @@ print( "Cython version {0} was found but won't be used: version {1} " "or greater is required because it offers a handy " - "parallelization module".format( - Cython.__version__, required_version - ) + "parallelization module".format(Cython.__version__, required_version) ) cython_found = False cython_linetrace = bool(os.environ.get("CYTHON_TRACE_NOGIL", False)) @@ -179,9 +177,7 @@ def get_numpy_include(): import numpy as np except ImportError: print('*** package "numpy" not found ***') - print( - "MDAnalysis requires a version of NumPy (>=1.21.0), even for setup." - ) + print("MDAnalysis requires a version of NumPy (>=1.21.0), even for setup.") print( "Please get it from http://numpy.scipy.org/ or install it through " "your package manager." @@ -456,12 +452,10 @@ def extensions(config): ap_clustering = MDAExtension( "MDAnalysis.analysis.encore.clustering.affinityprop", sources=[ - "MDAnalysis/analysis/encore/clustering/affinityprop" - + source_suffix, + "MDAnalysis/analysis/encore/clustering/affinityprop" + source_suffix, "MDAnalysis/analysis/encore/clustering/src/ap.c", ], - include_dirs=include_dirs - + ["MDAnalysis/analysis/encore/clustering/include"], + include_dirs=include_dirs + ["MDAnalysis/analysis/encore/clustering/include"], libraries=mathlib, define_macros=define_macros, extra_compile_args=encore_compile_args, @@ -605,9 +599,7 @@ def dynamic_author_list(): # Write the list of authors as a python list template = "__authors__ = [\n{}\n]" - author_string = ",\n".join( - ' u"{}"'.format(name) for name in authors - ) + author_string = ",\n".join(' u"{}"'.format(name) for name in authors) print(template.format(author_string), file=outfile) @@ -617,9 +609,7 @@ def long_description(readme): with open(abspath(readme)) as summary: buffer = summary.read() # remove top heading that messes up pypi display - m = re.search( - "====*\n[^\n]*README[^\n]*\n=====*\n", buffer, flags=re.DOTALL - ) + m = re.search("====*\n[^\n]*README[^\n]*\n=====*\n", buffer, flags=re.DOTALL) assert m, "README.rst does not contain a level-1 heading" return buffer[m.end() :] @@ -656,10 +646,7 @@ def long_description(readme): ) # Releases keep their cythonized stuff for shipping. - if ( - not config.get("keep_cythonized", default=is_release) - and not cython_linetrace - ): + if not config.get("keep_cythonized", default=is_release) and not cython_linetrace: for cythonized in cythonfiles: try: os.unlink(cythonized) diff --git a/testsuite/MDAnalysisTests/analysis/test_align.py b/testsuite/MDAnalysisTests/analysis/test_align.py index fbda36b158..37a5bccfea 100644 --- a/testsuite/MDAnalysisTests/analysis/test_align.py +++ b/testsuite/MDAnalysisTests/analysis/test_align.py @@ -99,14 +99,10 @@ def reference(): @staticmethod @pytest.fixture() def reference_small(reference): - return mda.Merge( - reference.select_atoms("not name H* and not atom 4AKE 1 CA") - ) + return mda.Merge(reference.select_atoms("not name H* and not atom 4AKE 1 CA")) @pytest.mark.parametrize("strict", (True, False)) - def test_match( - self, universe, reference, strict, selection="protein and backbone" - ): + def test_match(self, universe, reference, strict, selection="protein and backbone"): ref = reference.select_atoms(selection) mobile = universe.select_atoms(selection) groups = align.get_matching_atoms(ref, mobile, strict=strict) @@ -126,9 +122,7 @@ def test_nomatch_atoms_raise( else: with pytest.warns(SelectionWarning): with pytest.raises(SelectionError): - groups = align.get_matching_atoms( - ref, mobile, strict=strict - ) + groups = align.get_matching_atoms(ref, mobile, strict=strict) @pytest.mark.parametrize("strict", (True, False)) def test_nomatch_residues_raise_empty( @@ -149,9 +143,7 @@ def test_nomatch_residues_raise_empty( else: with pytest.warns(SelectionWarning): with pytest.raises(SelectionError): - groups = align.get_matching_atoms( - ref, mobile, strict=strict - ) + groups = align.get_matching_atoms(ref, mobile, strict=strict) def test_toggle_atom_mismatch_default_error(self, universe, reference): selection = ("resname ALA and name CA", "resname ALA and name O") @@ -167,9 +159,7 @@ def test_toggle_atom_mismatch_kwarg_error(self, universe, reference): def test_toggle_atom_nomatch(self, universe, reference): selection = ("resname ALA and name CA", "resname ALA and name O") - rmsd = align.alignto( - universe, reference, select=selection, match_atoms=False - ) + rmsd = align.alignto(universe, reference, select=selection, match_atoms=False) assert rmsd[0] > 0.01 def test_toggle_atom_nomatch_mismatch_atoms(self, universe, reference): @@ -191,28 +181,20 @@ def test_toggle_atom_nomatch_mismatch_atoms(self, universe, reference): (1234, pytest.raises(TypeError)), ], ) - def test_subselection_alignto( - self, universe, reference, subselection, expectation - ): + def test_subselection_alignto(self, universe, reference, subselection, expectation): with expectation: - rmsd = align.alignto( - universe, reference, subselection=subselection - ) + rmsd = align.alignto(universe, reference, subselection=subselection) assert_allclose(rmsd[1], 0.0, rtol=0, atol=1.5e-9) def test_no_atom_masses(self, universe): # if no masses are present - u = mda.Universe.empty( - 6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True - ) + u = mda.Universe.empty(6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True) with pytest.warns(SelectionWarning): align.get_matching_atoms(u.atoms, u.atoms) def test_one_universe_has_masses(self, universe): - u = mda.Universe.empty( - 6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True - ) + u = mda.Universe.empty(6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True) ref = mda.Universe.empty( 6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True ) @@ -277,9 +259,7 @@ def test_rmsd_custom_mass_weights(self, universe, reference): last_atoms_weight = universe.atoms.masses A = universe.trajectory[0] B = reference.trajectory[-1] - rmsd = align.alignto( - universe, reference, weights=reference.atoms.masses - ) + rmsd = align.alignto(universe, reference, weights=reference.atoms.masses) rmsd_sup_weight = rms.rmsd( A, B, weights=last_atoms_weight, center=True, superposition=True ) @@ -302,9 +282,7 @@ def test_AlignTraj_outfile_default(self, universe, reference, tmpdir): finally: x._writer.close() - def test_AlignTraj_outfile_default_exists( - self, universe, reference, tmpdir - ): + def test_AlignTraj_outfile_default_exists(self, universe, reference, tmpdir): reference.trajectory[-1] outfile = str(tmpdir.join("align_test.dcd")) align.AlignTraj(universe, reference, filename=outfile).run() @@ -356,16 +334,12 @@ def test_AlignTraj(self, universe, reference, tmpdir): def test_AlignTraj_weighted(self, universe, reference, tmpdir): outfile = str(tmpdir.join("align_test.dcd")) - x = align.AlignTraj( - universe, reference, filename=outfile, weights="mass" - ).run() + x = align.AlignTraj(universe, reference, filename=outfile, weights="mass").run() fitted = mda.Universe(PSF, outfile) assert_allclose(x.results.rmsd[0], 0, rtol=0, atol=1.5e-3) assert_allclose(x.results.rmsd[-1], 6.9033, rtol=0, atol=1.5e-3) - self._assert_rmsd( - reference, fitted, 0, 0.0, weights=universe.atoms.masses - ) + self._assert_rmsd(reference, fitted, 0, 0.0, weights=universe.atoms.masses) self._assert_rmsd( reference, fitted, @@ -388,9 +362,7 @@ def test_AlignTraj_custom_weights(self, universe, reference, tmpdir): universe, reference, filename=outfile, weights=weights ).run() - assert_allclose( - x.results.rmsd, x_weights.results.rmsd, rtol=0, atol=1.5e-7 - ) + assert_allclose(x.results.rmsd, x_weights.results.rmsd, rtol=0, atol=1.5e-7) def test_AlignTraj_custom_mass_weights(self, universe, reference, tmpdir): outfile = str(tmpdir.join("align_test.dcd")) @@ -404,9 +376,7 @@ def test_AlignTraj_custom_mass_weights(self, universe, reference, tmpdir): assert_allclose(x.results.rmsd[0], 0, rtol=0, atol=1.5e-3) assert_allclose(x.results.rmsd[-1], 6.9033, rtol=0, atol=1.5e-3) - self._assert_rmsd( - reference, fitted, 0, 0.0, weights=universe.atoms.masses - ) + self._assert_rmsd(reference, fitted, 0, 0.0, weights=universe.atoms.masses) self._assert_rmsd( reference, fitted, @@ -430,9 +400,7 @@ def test_AlignTraj_partial_fit(self, universe, reference, tmpdir): def test_AlignTraj_in_memory(self, universe, reference, tmpdir): outfile = str(tmpdir.join("align_test.dcd")) reference.trajectory[-1] - x = align.AlignTraj( - universe, reference, filename=outfile, in_memory=True - ).run() + x = align.AlignTraj(universe, reference, filename=outfile, in_memory=True).run() assert x.filename is None assert_allclose(x.results.rmsd[0], 6.9290, rtol=0, atol=1.5e-3) assert_allclose(x.results.rmsd[-1], 5.2797e-07, rtol=0, atol=1.5e-3) @@ -467,8 +435,7 @@ def _assert_rmsd(self, reference, fitted, frame, desired, weights=None): desired, rtol=0, atol=1.5e-5, - err_msg="frame {0:d} of fit does not have " - "expected RMSD".format(frame), + err_msg="frame {0:d} of fit does not have " "expected RMSD".format(frame), ) def test_alignto_checks_selections(self, universe, reference): @@ -502,9 +469,7 @@ def test_alignto_partial_universe(self, universe, reference): segB_free.translate(segB_bound.centroid() - segB_free.centroid()) align.alignto(u_free, u_bound, select=selection) - assert_allclose( - segB_bound.positions, segB_free.positions, rtol=0, atol=1.5e-3 - ) + assert_allclose(segB_bound.positions, segB_free.positions, rtol=0, atol=1.5e-3) def _get_aligned_average_positions(ref_files, ref, select="all", **kwargs): @@ -550,9 +515,7 @@ def test_average_structure_deprecated_attrs(self, universe, reference): def test_average_structure(self, universe, reference): ref, rmsd = _get_aligned_average_positions(self.ref_files, reference) avg = align.AverageStructure(universe, reference).run() - assert_allclose( - avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 - ) + assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_mass_weighted(self, universe, reference): @@ -560,9 +523,7 @@ def test_average_structure_mass_weighted(self, universe, reference): self.ref_files, reference, weights="mass" ) avg = align.AverageStructure(universe, reference, weights="mass").run() - assert_allclose( - avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 - ) + assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_select(self, universe, reference): @@ -571,17 +532,13 @@ def test_average_structure_select(self, universe, reference): self.ref_files, reference, select=select ) avg = align.AverageStructure(universe, reference, select=select).run() - assert_allclose( - avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 - ) + assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_no_ref(self, universe): ref, rmsd = _get_aligned_average_positions(self.ref_files, universe) avg = align.AverageStructure(universe).run() - assert_allclose( - avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 - ) + assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_no_msf(self, universe): @@ -605,9 +562,7 @@ def test_average_structure_ref_frame(self, universe): universe.trajectory[0] ref, rmsd = _get_aligned_average_positions(self.ref_files, u) avg = align.AverageStructure(universe, ref_frame=ref_frame).run() - assert_allclose( - avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 - ) + assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_in_memory(self, universe): diff --git a/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py b/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py index 4697485470..9e8341bf7d 100644 --- a/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py +++ b/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py @@ -79,9 +79,7 @@ def ad_ag4(): @staticmethod @pytest.fixture() def expected_dist(ad_ag1, ad_ag2): - expected = np.zeros( - (len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms) - ) + expected = np.zeros((len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms)) # calculate distances without PBCs using dist() for i, ts in enumerate(ad_ag1.universe.trajectory): @@ -91,9 +89,7 @@ def expected_dist(ad_ag1, ad_ag2): @staticmethod @pytest.fixture() def expected_pbc_dist(ad_ag1, ad_ag2): - expected = np.zeros( - (len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms) - ) + expected = np.zeros((len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms)) # calculate distances with PBCs using dist() for i, ts in enumerate(ad_ag1.universe.trajectory): diff --git a/testsuite/MDAnalysisTests/analysis/test_base.py b/testsuite/MDAnalysisTests/analysis/test_base.py index 0dd872bde5..eada555174 100644 --- a/testsuite/MDAnalysisTests/analysis/test_base.py +++ b/testsuite/MDAnalysisTests/analysis/test_base.py @@ -56,9 +56,7 @@ def _conclude(self): self.found_frames = list(self.results.found_frames) def _get_aggregator(self): - return base.ResultsGroup( - {"found_frames": base.ResultsGroup.ndarray_hstack} - ) + return base.ResultsGroup({"found_frames": base.ResultsGroup.ndarray_hstack}) class IncompleteAnalysis(base.AnalysisBase): @@ -173,9 +171,7 @@ def test_n_workers_conflict_raises_value_error(u): def test_backend_configuration_fails(u, run_class, backend, n_workers): u = mda.Universe(TPR, XTC) # dt = 100 with pytest.raises(ValueError): - _ = run_class(u.trajectory).run( - backend=backend, n_workers=n_workers, stop=0 - ) + _ = run_class(u.trajectory).run(backend=backend, n_workers=n_workers, stop=0) @pytest.mark.parametrize( @@ -221,9 +217,7 @@ def test_custom_backend_works(u, run_class, backend, n_workers): (ParallelizableWithDaskOnly, object, 1), ], ) -def test_fails_incorrect_custom_backend( - u, run_class, backend_instance, n_workers -): +def test_fails_incorrect_custom_backend(u, run_class, backend_instance, n_workers): u = mda.Universe(TPR, XTC) # dt = 100 with pytest.raises(ValueError): _ = run_class(u.trajectory).run( @@ -233,9 +227,7 @@ def test_fails_incorrect_custom_backend( ) with pytest.raises(ValueError): - _ = run_class(u.trajectory).run( - backend=backend_instance, n_workers=n_workers - ) + _ = run_class(u.trajectory).run(backend=backend_instance, n_workers=n_workers) @pytest.mark.parametrize( @@ -289,9 +281,7 @@ def test_reset_n_parts_to_n_frames(u): """ a = FrameAnalysis(u.trajectory) with pytest.warns(UserWarning, match="Set `n_parts` to"): - a.run( - backend="multiprocessing", start=0, stop=1, n_workers=2, n_parts=2 - ) + a.run(backend="multiprocessing", start=0, stop=1, n_workers=2, n_parts=2) @pytest.mark.parametrize( @@ -308,9 +298,7 @@ def test_start_stop_step(u, run_kwargs, frames): assert an.n_frames == len(frames) assert_equal(an.found_frames, frames) assert_equal(an.frames, frames, err_msg=FRAMES_ERR) - assert_allclose( - an.times, frames + 1, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR - ) + assert_allclose(an.times, frames + 1, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR) @pytest.mark.parametrize( @@ -438,9 +426,7 @@ def test_frame_bool_fail(client_FrameAnalysis): def test_rewind(client_FrameAnalysis): u = mda.Universe(TPR, XTC) # dt = 100 - an = FrameAnalysis(u.trajectory).run( - **client_FrameAnalysis, frames=[0, 2, 3, 5, 9] - ) + an = FrameAnalysis(u.trajectory).run(**client_FrameAnalysis, frames=[0, 2, 3, 5, 9]) assert_equal(u.trajectory.ts.frame, 0) @@ -453,9 +439,7 @@ def test_frames_times(client_FrameAnalysis): assert an.n_frames == len(frames) assert_equal(an.found_frames, frames) assert_equal(an.frames, frames, err_msg=FRAMES_ERR) - assert_allclose( - an.times, frames * 100, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR - ) + assert_allclose(an.times, frames * 100, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR) def test_verbose(u): @@ -498,9 +482,7 @@ def test_verbose_progressbar_run(u, capsys): def test_verbose_progressbar_run_with_kwargs(u, capsys): - FrameAnalysis(u.trajectory).run( - verbose=True, progressbar_kwargs={"desc": "custom"} - ) + FrameAnalysis(u.trajectory).run(verbose=True, progressbar_kwargs={"desc": "custom"}) _, err = capsys.readouterr() expected = "custom: 100%|██████████" actual = err.strip().split("\r")[-1] @@ -509,9 +491,7 @@ def test_verbose_progressbar_run_with_kwargs(u, capsys): def test_progressbar_multiprocessing(u): with pytest.raises(ValueError): - FrameAnalysis(u.trajectory).run( - backend="multiprocessing", verbose=True - ) + FrameAnalysis(u.trajectory).run(backend="multiprocessing", verbose=True) def test_incomplete_defined_analysis(u): @@ -626,9 +606,7 @@ def test_analysis_class(client_AnalysisFromFunctionAnalysisClass): u = mda.Universe(PSF, DCD) step = 2 - ana = ana_class(u.atoms).run( - step=step, **client_AnalysisFromFunctionAnalysisClass - ) + ana = ana_class(u.atoms).run(step=step, **client_AnalysisFromFunctionAnalysisClass) results = [] for ts in u.trajectory[::step]: diff --git a/testsuite/MDAnalysisTests/analysis/test_bat.py b/testsuite/MDAnalysisTests/analysis/test_bat.py index 704cf616cb..91c040646a 100644 --- a/testsuite/MDAnalysisTests/analysis/test_bat.py +++ b/testsuite/MDAnalysisTests/analysis/test_bat.py @@ -70,9 +70,7 @@ def test_bat_root_selection(self, selected_residues): ) def test_bat_number_of_frames(self, bat): - assert_equal( - len(bat), 2, err_msg="error: list is not length of trajectory" - ) + assert_equal(len(bat), 2, err_msg="error: list is not length of trajectory") def test_bat_coordinates(self, bat): test_bat = np.load(BATArray) @@ -85,11 +83,7 @@ def test_bat_coordinates(self, bat): ) def test_bat_coordinates_single_frame(self, selected_residues, client_BAT): - bat = ( - BAT(selected_residues) - .run(start=1, stop=2, **client_BAT) - .results.bat - ) + bat = BAT(selected_residues).run(start=1, stop=2, **client_BAT).results.bat test_bat = [np.load(BATArray)[1]] assert_allclose( bat, @@ -135,9 +129,7 @@ def test_bat_bad_initial_atom(self, selected_residues): def test_bat_disconnected_atom_group(self): u = mda.Universe(PSF, DCD) - selected_residues = u.select_atoms("resid 1-3") + u.select_atoms( - "resid 5-7" - ) + selected_residues = u.select_atoms("resid 1-3") + u.select_atoms("resid 5-7") errmsg = "Additional torsions not found." with pytest.raises(ValueError, match=errmsg): R = BAT(selected_residues) diff --git a/testsuite/MDAnalysisTests/analysis/test_contacts.py b/testsuite/MDAnalysisTests/analysis/test_contacts.py index 7f4a5b69ec..7868acc5e9 100644 --- a/testsuite/MDAnalysisTests/analysis/test_contacts.py +++ b/testsuite/MDAnalysisTests/analysis/test_contacts.py @@ -206,9 +206,7 @@ def test_contacts_selections(self, universe, client_Contacts): aga = universe.select_atoms(self.sel_acidic) agb = universe.select_atoms(self.sel_basic) - cag = contacts.Contacts( - universe, select=(aga, agb), refgroup=(aga, agb) - ) + cag = contacts.Contacts(universe, select=(aga, agb), refgroup=(aga, agb)) csel = contacts.Contacts( universe, @@ -244,9 +242,7 @@ def test_startframe(self, universe, client_Contacts): def test_end_zero(self, universe, client_Contacts): """test_end_zero: TestContactAnalysis1: stop frame 0 is not ignored""" - CA1 = self._run_Contacts( - universe, client_Contacts=client_Contacts, stop=0 - ) + CA1 = self._run_Contacts(universe, client_Contacts=client_Contacts, stop=0) assert len(CA1.results.timeseries) == 0 def test_slicing(self, universe, client_Contacts): @@ -275,9 +271,7 @@ def test_villin_folded(self, client_Contacts): q.run(**client_Contacts) results = soft_cut(f, u, sel, sel) - assert_allclose( - q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7 - ) + assert_allclose(q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7) def test_villin_unfolded(self, client_Contacts): # both folded @@ -293,9 +287,7 @@ def test_villin_unfolded(self, client_Contacts): q.run(**client_Contacts) results = soft_cut(f, u, sel, sel) - assert_allclose( - q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7 - ) + assert_allclose(q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7) def test_hard_cut_method(self, universe, client_Contacts): ca = self._run_Contacts(universe, client_Contacts=client_Contacts) @@ -324,9 +316,7 @@ def test_hard_cut_method(self, universe, client_Contacts): ] # fmt: on assert len(ca.results.timeseries) == len(expected) - assert_allclose( - ca.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7 - ) + assert_allclose(ca.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7) def test_radius_cut_method(self, universe, client_Contacts): acidic = universe.select_atoms(self.sel_acidic) @@ -438,16 +428,12 @@ def test_distance_box(self, pbc, expected, client_Contacts): pbc=pbc, ) r.run(**client_Contacts) - assert_allclose( - r.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7 - ) + assert_allclose(r.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7) def test_warn_deprecated_attr(self, universe, client_Contacts): """Test for warning message emitted on using deprecated `timeseries` attribute""" - CA1 = self._run_Contacts( - universe, client_Contacts=client_Contacts, stop=1 - ) + CA1 = self._run_Contacts(universe, client_Contacts=client_Contacts, stop=1) wmsg = "The `timeseries` attribute was deprecated in MDAnalysis" with pytest.warns(DeprecationWarning, match=wmsg): assert_equal(CA1.timeseries, CA1.results.timeseries) @@ -494,9 +480,7 @@ def test_q1q2(client_Contacts): 0.93006358, 0.9346049, 0.93188011, ] # fmt: on - assert_allclose( - q1q2.results.timeseries[:, 1], q1_expected, rtol=0, atol=1.5e-7 - ) + assert_allclose(q1q2.results.timeseries[:, 1], q1_expected, rtol=0, atol=1.5e-7) # fmt: off q2_expected = [ @@ -522,6 +506,4 @@ def test_q1q2(client_Contacts): 0.98616236, 0.9898524, 1.0, ] # fmt: on - assert_allclose( - q1q2.results.timeseries[:, 2], q2_expected, rtol=0, atol=1.5e-7 - ) + assert_allclose(q1q2.results.timeseries[:, 2], q2_expected, rtol=0, atol=1.5e-7) diff --git a/testsuite/MDAnalysisTests/analysis/test_density.py b/testsuite/MDAnalysisTests/analysis/test_density.py index 3547ff9fe9..7511f997a3 100644 --- a/testsuite/MDAnalysisTests/analysis/test_density.py +++ b/testsuite/MDAnalysisTests/analysis/test_density.py @@ -51,9 +51,7 @@ def bins(self): def h_and_edges(self, bins): return np.histogramdd( self.Lmax - * np.sin(np.linspace(0, 1, self.counts * 3)).reshape( - self.counts, 3 - ), + * np.sin(np.linspace(0, 1, self.counts * 3)).reshape(self.counts, 3), bins=bins, ) @@ -241,9 +239,7 @@ class DensityParameters(object): @pytest.fixture() def universe(self): - return mda.Universe( - self.topology, self.trajectory, tpr_resid_from_one=False - ) + return mda.Universe(self.topology, self.trajectory, tpr_resid_from_one=False) class TestDensityAnalysis(DensityParameters): @@ -369,9 +365,7 @@ def test_ValueError_userdefn_gridcenter_shape( self, universe, client_DensityAnalysis ): # Test len(gridcenter) != 3 - with pytest.raises( - ValueError, match="Gridcenter must be a 3D coordinate" - ): + with pytest.raises(ValueError, match="Gridcenter must be a 3D coordinate"): D = density.DensityAnalysis( universe.select_atoms(self.selections["static"]), delta=self.delta, @@ -385,9 +379,7 @@ def test_ValueError_userdefn_gridcenter_type( self, universe, client_DensityAnalysis ): # Test gridcenter includes non-numeric strings - with pytest.raises( - ValueError, match="Gridcenter must be a 3D coordinate" - ): + with pytest.raises(ValueError, match="Gridcenter must be a 3D coordinate"): D = density.DensityAnalysis( universe.select_atoms(self.selections["static"]), delta=self.delta, @@ -411,13 +403,9 @@ def test_ValueError_userdefn_gridcenter_missing( zdim=10.0, ).run(step=5, **client_DensityAnalysis) - def test_ValueError_userdefn_xdim_type( - self, universe, client_DensityAnalysis - ): + def test_ValueError_userdefn_xdim_type(self, universe, client_DensityAnalysis): # Test xdim != int or float - with pytest.raises( - ValueError, match="xdim, ydim, and zdim must be numbers" - ): + with pytest.raises(ValueError, match="xdim, ydim, and zdim must be numbers"): D = density.DensityAnalysis( universe.select_atoms(self.selections["static"]), delta=self.delta, @@ -427,9 +415,7 @@ def test_ValueError_userdefn_xdim_type( gridcenter=self.gridcenters["static_defined"], ).run(step=5, **client_DensityAnalysis) - def test_ValueError_userdefn_xdim_nanvalue( - self, universe, client_DensityAnalysis - ): + def test_ValueError_userdefn_xdim_nanvalue(self, universe, client_DensityAnalysis): # Test xdim set to NaN value regex = "Gridcenter or grid dimensions have NaN element" with pytest.raises(ValueError, match=regex): @@ -476,9 +462,7 @@ def test_ValueError_noatomgroup(self, universe, client_DensityAnalysis): ).run(step=5, **client_DensityAnalysis) def test_warn_results_deprecated(self, universe, client_DensityAnalysis): - D = density.DensityAnalysis( - universe.select_atoms(self.selections["static"]) - ) + D = density.DensityAnalysis(universe.select_atoms(self.selections["static"])) D.run(stop=1, **client_DensityAnalysis) wmsg = "The `density` attribute was deprecated in MDAnalysis 2.0.0" with pytest.warns(DeprecationWarning, match=wmsg): diff --git a/testsuite/MDAnalysisTests/analysis/test_dielectric.py b/testsuite/MDAnalysisTests/analysis/test_dielectric.py index 45d8e722cd..ba19e40780 100644 --- a/testsuite/MDAnalysisTests/analysis/test_dielectric.py +++ b/testsuite/MDAnalysisTests/analysis/test_dielectric.py @@ -58,9 +58,7 @@ def test_temperature(self, ag): def test_non_charges(self): u = mda.Universe(DCD_TRICLINIC, to_guess=()) - with pytest.raises( - NoDataError, match="No charges defined given atomgroup." - ): + with pytest.raises(NoDataError, match="No charges defined given atomgroup."): DielectricConstant(u.atoms).run() def test_non_neutral(self, ag): diff --git a/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py b/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py index 99e978b3ff..b8c1265d8f 100644 --- a/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py +++ b/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py @@ -55,9 +55,7 @@ def test_eg(dist, dmap): def test_dist_weights(u): backbone = u.select_atoms("backbone") weights_atoms = np.ones(len(backbone.atoms)) - dist = diffusionmap.DistanceMatrix( - u, select="backbone", weights=weights_atoms - ) + dist = diffusionmap.DistanceMatrix(u, select="backbone", weights=weights_atoms) dist.run(step=3) dmap = diffusionmap.DiffusionMap(dist) dmap.run() @@ -79,9 +77,7 @@ def test_dist_weights(u): def test_dist_weights_frames(u): backbone = u.select_atoms("backbone") weights_atoms = np.ones(len(backbone.atoms)) - dist = diffusionmap.DistanceMatrix( - u, select="backbone", weights=weights_atoms - ) + dist = diffusionmap.DistanceMatrix(u, select="backbone", weights=weights_atoms) frames = np.arange(len(u.trajectory)) dist.run(frames=frames[::3]) dmap = diffusionmap.DiffusionMap(dist) @@ -105,18 +101,14 @@ def test_distvalues_ag_universe(u): dist_universe = diffusionmap.DistanceMatrix(u, select="backbone").run() ag = u.select_atoms("backbone") dist_ag = diffusionmap.DistanceMatrix(ag).run() - assert_allclose( - dist_universe.results.dist_matrix, dist_ag.results.dist_matrix - ) + assert_allclose(dist_universe.results.dist_matrix, dist_ag.results.dist_matrix) def test_distvalues_ag_select(u): dist_universe = diffusionmap.DistanceMatrix(u, select="backbone").run() ag = u.select_atoms("protein") dist_ag = diffusionmap.DistanceMatrix(ag, select="backbone").run() - assert_allclose( - dist_universe.results.dist_matrix, dist_ag.results.dist_matrix - ) + assert_allclose(dist_universe.results.dist_matrix, dist_ag.results.dist_matrix) def test_different_steps(u): diff --git a/testsuite/MDAnalysisTests/analysis/test_dihedrals.py b/testsuite/MDAnalysisTests/analysis/test_dihedrals.py index 82625dfb93..62efb550b5 100644 --- a/testsuite/MDAnalysisTests/analysis/test_dihedrals.py +++ b/testsuite/MDAnalysisTests/analysis/test_dihedrals.py @@ -48,9 +48,7 @@ class TestDihedral(object): @pytest.fixture() def atomgroup(self): u = mda.Universe(GRO, XTC) - ag = u.select_atoms( - "(resid 4 and name N CA C) or (resid 5 and name N)" - ) + ag = u.select_atoms("(resid 4 and name N CA C) or (resid 5 and name N)") return ag def test_dihedral(self, atomgroup, client_Dihedral): @@ -72,9 +70,7 @@ def test_dihedral(self, atomgroup, client_Dihedral): ) def test_dihedral_single_frame(self, atomgroup, client_Dihedral): - dihedral = Dihedral([atomgroup]).run( - start=5, stop=6, **client_Dihedral - ) + dihedral = Dihedral([atomgroup]).run(start=5, stop=6, **client_Dihedral) test_dihedral = [np.load(DihedralArray)[5]] assert_allclose( @@ -120,9 +116,7 @@ def rama_ref_array(self): return np.load(RamaArray) def test_ramachandran(self, universe, rama_ref_array, client_Ramachandran): - rama = Ramachandran(universe.select_atoms("protein")).run( - **client_Ramachandran - ) + rama = Ramachandran(universe.select_atoms("protein")).run(**client_Ramachandran) assert_allclose( rama.results.angles, @@ -147,9 +141,7 @@ def test_ramachandran_single_frame( err_msg="error: dihedral angles should " "match test values", ) - def test_ramachandran_residue_selections( - self, universe, client_Ramachandran - ): + def test_ramachandran_residue_selections(self, universe, client_Ramachandran): rama = Ramachandran(universe.select_atoms("resname GLY")).run( **client_Ramachandran ) @@ -187,11 +179,7 @@ def test_None_removal(self): rama = Ramachandran(u.select_atoms("protein").residues[1:-1]) def test_plot(self, universe): - ax = ( - Ramachandran(universe.select_atoms("resid 5-10")) - .run() - .plot(ref=True) - ) + ax = Ramachandran(universe.select_atoms("resid 5-10")).run().plot(ref=True) assert isinstance( ax, matplotlib.axes.Axes ), "Ramachandran.plot() did not return and Axes instance" @@ -272,9 +260,7 @@ def test_atom_selection(self): with pytest.raises(ValueError): u = mda.Universe(PDB_janin) janin = Janin( - u.select_atoms( - "protein and not resname ALA CYS GLY " "PRO SER THR VAL" - ) + u.select_atoms("protein and not resname ALA CYS GLY " "PRO SER THR VAL") ) def test_plot(self, universe): diff --git a/testsuite/MDAnalysisTests/analysis/test_distances.py b/testsuite/MDAnalysisTests/analysis/test_distances.py index 90fe8d75e8..0a466b1ab4 100644 --- a/testsuite/MDAnalysisTests/analysis/test_distances.py +++ b/testsuite/MDAnalysisTests/analysis/test_distances.py @@ -96,36 +96,28 @@ def test_np(self, coord, shape, res_no_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, cutoff=1, returntype="numpy" ) - assert contacts.shape == shape, "wrong shape (should be {0})".format( - shape - ) + assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) assert_equal(contacts, res_no_pbc) def test_sparse(self, coord, shape, res_no_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, cutoff=1.5, returntype="sparse" ) - assert contacts.shape == shape, "wrong shape (should be {0})".format( - shape - ) + assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) assert_equal(contacts.toarray(), res_no_pbc) def test_box_numpy(self, coord, box, shape, res_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, box=box, cutoff=1 ) - assert contacts.shape == shape, "wrong shape (should be {0})".format( - shape - ) + assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) assert_equal(contacts, res_pbc) def test_box_sparse(self, coord, box, shape, res_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, box=box, cutoff=1, returntype="sparse" ) - assert contacts.shape == shape, "wrong shape (should be {0})".format( - shape - ) + assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) assert_equal(contacts.toarray(), res_pbc) @@ -153,9 +145,7 @@ def box(): @pytest.fixture() def expected(ag, ag2): - return np.diag( - scipy.spatial.distance.cdist(ag.positions, ag2.positions) - ) + return np.diag(scipy.spatial.distance.cdist(ag.positions, ag2.positions)) @staticmethod @pytest.fixture() @@ -187,9 +177,7 @@ def test_pairwise_dist_offset_effect(self, ag, ag2, expected): def test_offset_calculation(self, ag, ag2): """Test that offsets fed to dist() are correctly calculated.""" actual = MDAnalysis.analysis.distances.dist(ag, ag2, offset=33)[:2] - assert_equal( - actual, np.array([ag.atoms.resids + 33, ag2.atoms.resids + 33]) - ) + assert_equal(actual, np.array([ag.atoms.resids + 33, ag2.atoms.resids + 33])) def test_mismatch_exception(self, ag, ag2, expected): """A ValueError should be raised if the two atomgroups @@ -223,9 +211,7 @@ def group(u): @pytest.fixture() def expected(self, group, ag, ag2): - distance_matrix_1 = scipy.spatial.distance.cdist( - group.positions, ag.positions - ) + distance_matrix_1 = scipy.spatial.distance.cdist(group.positions, ag.positions) mask_1 = np.unique(np.where(distance_matrix_1 <= self.distance)[0]) group_filtered = group[mask_1] distance_matrix_2 = scipy.spatial.distance.cdist( diff --git a/testsuite/MDAnalysisTests/analysis/test_dssp.py b/testsuite/MDAnalysisTests/analysis/test_dssp.py index ee43a400df..7b132d0032 100644 --- a/testsuite/MDAnalysisTests/analysis/test_dssp.py +++ b/testsuite/MDAnalysisTests/analysis/test_dssp.py @@ -9,9 +9,7 @@ # Files that match glob pattern '????.pdb.gz' and matching '????.pdb.dssp' files, # containing the secondary structure assignment string, will be tested automatically. -@pytest.mark.parametrize( - "pdb_filename", glob.glob(f"{DSSP_FOLDER}/?????.pdb.gz") -) +@pytest.mark.parametrize("pdb_filename", glob.glob(f"{DSSP_FOLDER}/?????.pdb.gz")) def test_file_guess_hydrogens(pdb_filename, client_DSSP): u = mda.Universe(pdb_filename) with open(f"{pdb_filename.rstrip('.gz')}.dssp", "r") as fin: @@ -29,9 +27,7 @@ def test_trajectory(client_DSSP): last_frame = "".join(run.results.dssp[-1]) avg_frame = "".join(translate(run.results.dssp_ndarray.mean(axis=0))) - assert ( - first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" - ) + assert first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" protein = mda.Universe(TPR, XTC).select_atoms("protein") run = DSSP(protein).run(**client_DSSP, stop=10) @@ -43,9 +39,7 @@ def test_atomgroup(client_DSSP): last_frame = "".join(run.results.dssp[-1]) avg_frame = "".join(translate(run.results.dssp_ndarray.mean(axis=0))) - assert ( - first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" - ) + assert first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" def test_trajectory_with_hydrogens(client_DSSP): @@ -55,14 +49,10 @@ def test_trajectory_with_hydrogens(client_DSSP): last_frame = "".join(run.results.dssp[-1]) avg_frame = "".join(translate(run.results.dssp_ndarray.mean(axis=0))) - assert ( - first_frame[:10] == last_frame[:10] == avg_frame[:10] == "-EEEEEE---" - ) + assert first_frame[:10] == last_frame[:10] == avg_frame[:10] == "-EEEEEE---" -@pytest.mark.parametrize( - "pdb_filename", glob.glob(f"{DSSP_FOLDER}/2xdgA.pdb.gz") -) +@pytest.mark.parametrize("pdb_filename", glob.glob(f"{DSSP_FOLDER}/2xdgA.pdb.gz")) def test_trajectory_without_hydrogen_fails(pdb_filename, client_DSSP): u = mda.Universe(pdb_filename) with pytest.raises(ValueError): @@ -72,9 +62,7 @@ def test_trajectory_without_hydrogen_fails(pdb_filename, client_DSSP): @pytest.mark.parametrize( "pdb_filename", glob.glob(f"{DSSP_FOLDER}/1mr1D_failing.pdb.gz") ) -def test_trajectory_with_uneven_number_of_atoms_fails( - pdb_filename, client_DSSP -): +def test_trajectory_with_uneven_number_of_atoms_fails(pdb_filename, client_DSSP): u = mda.Universe(pdb_filename) with pytest.raises(ValueError): DSSP(u, guess_hydrogens=True).run(**client_DSSP) diff --git a/testsuite/MDAnalysisTests/analysis/test_encore.py b/testsuite/MDAnalysisTests/analysis/test_encore.py index 9204352f48..ee2d493bc0 100644 --- a/testsuite/MDAnalysisTests/analysis/test_encore.py +++ b/testsuite/MDAnalysisTests/analysis/test_encore.py @@ -90,9 +90,7 @@ def test_triangular_matrix(self): triangular_matrix[0, 1] = expected_value - err_msg = ( - "Data error in TriangularMatrix: read/write are not consistent" - ) + err_msg = "Data error in TriangularMatrix: read/write are not consistent" assert_equal(triangular_matrix[0, 1], expected_value, err_msg) assert_equal( @@ -169,23 +167,18 @@ def test_parallel_calculation(self): ) def test_rmsd_matrix_with_superimposition(self, ens1): - conf_dist_matrix = ( - encore.confdistmatrix.conformational_distance_matrix( - ens1, - encore.confdistmatrix.set_rmsd_matrix_elements, - select="name CA", - pairwise_align=True, - weights="mass", - n_jobs=1, - ) + conf_dist_matrix = encore.confdistmatrix.conformational_distance_matrix( + ens1, + encore.confdistmatrix.set_rmsd_matrix_elements, + select="name CA", + pairwise_align=True, + weights="mass", + n_jobs=1, ) reference = rms.RMSD(ens1, select="name CA") reference.run() - err_msg = ( - "Calculated RMSD values differ from " - "the reference implementation" - ) + err_msg = "Calculated RMSD values differ from " "the reference implementation" for i, rmsd in enumerate(reference.results.rmsd): assert_allclose( conf_dist_matrix[0, i], @@ -196,29 +189,25 @@ def test_rmsd_matrix_with_superimposition(self, ens1): ) def test_rmsd_matrix_with_superimposition_custom_weights(self, ens1): - conf_dist_matrix = ( - encore.confdistmatrix.conformational_distance_matrix( - ens1, - encore.confdistmatrix.set_rmsd_matrix_elements, - select="name CA", - pairwise_align=True, - weights="mass", - n_jobs=1, - ) + conf_dist_matrix = encore.confdistmatrix.conformational_distance_matrix( + ens1, + encore.confdistmatrix.set_rmsd_matrix_elements, + select="name CA", + pairwise_align=True, + weights="mass", + n_jobs=1, ) - conf_dist_matrix_custom = ( - encore.confdistmatrix.conformational_distance_matrix( - ens1, - encore.confdistmatrix.set_rmsd_matrix_elements, - select="name CA", - pairwise_align=True, - weights=( - ens1.select_atoms("name CA").masses, - ens1.select_atoms("name CA").masses, - ), - n_jobs=1, - ) + conf_dist_matrix_custom = encore.confdistmatrix.conformational_distance_matrix( + ens1, + encore.confdistmatrix.set_rmsd_matrix_elements, + select="name CA", + pairwise_align=True, + weights=( + ens1.select_atoms("name CA").masses, + ens1.select_atoms("name CA").masses, + ), + n_jobs=1, ) for i in range(conf_dist_matrix_custom.size): @@ -235,9 +224,7 @@ def test_rmsd_matrix_without_superimposition(self, ens1): reference_rmsd = [] coordinates = ens1.trajectory.timeseries(selection, order="fac") for coord in coordinates: - reference_rmsd.append( - rms.rmsd(coordinates[0], coord, superposition=False) - ) + reference_rmsd.append(rms.rmsd(coordinates[0], coord, superposition=False)) confdist_matrix = encore.confdistmatrix.conformational_distance_matrix( ens1, @@ -360,12 +347,8 @@ def test_covariance_matrix_with_reference(self, ens1): estimator=encore.covariance.shrinkage_covariance_estimator, reference=ens1, ) - err_msg = ( - "Covariance matrix from covariance estimation not as expected" - ) - assert_allclose( - covariance, reference_cov, rtol=0, atol=1.5e-4, err_msg=err_msg - ) + err_msg = "Covariance matrix from covariance estimation not as expected" + assert_allclose(covariance, reference_cov, rtol=0, atol=1.5e-4, err_msg=err_msg) def test_hes_to_self(self, ens1): results, details = encore.hes([ens1, ens1]) @@ -425,9 +408,7 @@ def test_hes_align(self, ens1, ens2): def test_ces_to_self(self, ens1): results, details = encore.ces( [ens1, ens1], - clustering_method=encore.AffinityPropagationNative( - preference=-3.0 - ), + clustering_method=encore.AffinityPropagationNative(preference=-3.0), ) result_value = results[0, 1] expected_value = 0.0 @@ -470,9 +451,7 @@ def test_dres_to_self(self, ens1): ) def test_dres(self, ens1, ens2): - results, details = encore.dres( - [ens1, ens2], select="name CA and resnum 1-10" - ) + results, details = encore.dres([ens1, ens2], select="name CA and resnum 1-10") result_value = results[0, 1] upper_bound = 0.6 assert result_value < upper_bound, ( @@ -487,9 +466,7 @@ def test_dres_without_superimposition(self, ens1, ens2): distance_matrix = encore.get_distance_matrix( encore.merge_universes([ens1, ens2]), superimpose=False ) - results, details = encore.dres( - [ens1, ens2], distance_matrix=distance_matrix - ) + results, details = encore.dres([ens1, ens2], distance_matrix=distance_matrix) result_value = results[0, 1] expected_value = 0.68 assert_allclose( @@ -521,9 +498,7 @@ def test_dres_convergence(self, ens1): expected_values = [0.3, 0.0] results = encore.dres_convergence(ens1, 10) try: - assert_allclose( - results[:, 0], expected_values, rtol=0, atol=1.5e-1 - ) + assert_allclose(results[:, 0], expected_values, rtol=0, atol=1.5e-1) except AssertionError: # Random test failure is very rare, but repeating the failed test # just once would only assert that the test passes with 50% @@ -566,12 +541,8 @@ def test_hes_error_estimation(self, ens1): "Unexpected standard deviation for bootstrapped samples in" " Harmonic Ensemble similarity" ) - assert_allclose( - average, expected_average, rtol=0, atol=1.5e2, err_msg=err_msg - ) - assert_allclose( - stdev, expected_stdev, rtol=0, atol=1.5e2, err_msg=error_msg - ) + assert_allclose(average, expected_average, rtol=0, atol=1.5e2, err_msg=err_msg) + assert_allclose(stdev, expected_stdev, rtol=0, atol=1.5e2, err_msg=error_msg) def test_ces_error_estimation(self, ens1): expected_average = 0.03 @@ -580,9 +551,7 @@ def test_ces_error_estimation(self, ens1): [ens1, ens1], estimate_error=True, bootstrapping_samples=10, - clustering_method=encore.AffinityPropagationNative( - preference=-2.0 - ), + clustering_method=encore.AffinityPropagationNative(preference=-2.0), select="name CA and resnum 1-10", ) average = averages[0, 1] @@ -625,16 +594,12 @@ def test_ces_error_estimation_ensemble_bootstrap(self, ens1): "Unexpected average value for bootstrapped samples in" " Clustering Ensemble similarity" ) - assert_allclose( - average, expected_average, rtol=0, atol=1.5e-1, err_msg=err_msg - ) + assert_allclose(average, expected_average, rtol=0, atol=1.5e-1, err_msg=err_msg) error_msg = ( "Unexpected standard deviation for bootstrapped samples in" " Clustering Ensemble similarity" ) - assert_allclose( - stdev, expected_stdev, rtol=0, atol=1.5e-1, err_msg=error_msg - ) + assert_allclose(stdev, expected_stdev, rtol=0, atol=1.5e-1, err_msg=error_msg) def test_dres_error_estimation(self, ens1): average_upper_bound = 0.3 @@ -806,9 +771,7 @@ def test_clustering_two_methods_one_w_no_distance_matrix(self, ens1): def test_sklearn_affinity_propagation(self, ens1): pytest.importorskip("sklearn") cc1 = encore.cluster([ens1]) - cc2 = encore.cluster( - [ens1], method=encore.AffinityPropagation(random_state=0) - ) + cc2 = encore.cluster([ens1], method=encore.AffinityPropagation(random_state=0)) assert len(cc1) == len(cc2), ( "Native and sklearn implementations of affinity " "propagation don't agree: mismatch in number of " @@ -852,8 +815,7 @@ def test_cluster_add_metadata(self, cluster): ) metadata = np.append(metadata, 9) error_message = ( - "Size of metadata is not equal to the " - "number of cluster elements" + "Size of metadata is not equal to the " "number of cluster elements" ) with pytest.raises(TypeError, match=error_message): cluster.add_metadata("test2", metadata) @@ -876,9 +838,7 @@ def test_metadata_size_error(self): "not equal to the number of cluster elements" ) with pytest.raises(TypeError, match=error_message): - encore.Cluster( - np.array([1, 1, 1]), 1, None, {"label": [1, 1, 1, 1]} - ) + encore.Cluster(np.array([1, 1, 1]), 1, None, {"label": [1, 1, 1, 1]}) def test_cluster_iteration(self, cluster): test = [] @@ -988,9 +948,7 @@ def distance_matrix(self): def test_one(self, distance_matrix): preference = -float(np.median(distance_matrix.as_array()) * 10.0) - clustering_method = encore.AffinityPropagationNative( - preference=preference - ) + clustering_method = encore.AffinityPropagationNative(preference=preference) ccs = encore.cluster( None, distance_matrix=distance_matrix, method=clustering_method ) @@ -1051,16 +1009,10 @@ def test_dimensionality_reduction_two_ensembles(self, ens1, ens2): ), ) - def test_dimensionality_reduction_three_ensembles_two_identical( - self, ens1, ens2 - ): + def test_dimensionality_reduction_three_ensembles_two_identical(self, ens1, ens2): coordinates, details = encore.reduce_dimensionality([ens1, ens2, ens1]) - coordinates_ens1 = coordinates[ - :, np.where(details["ensemble_membership"] == 1) - ] - coordinates_ens3 = coordinates[ - :, np.where(details["ensemble_membership"] == 3) - ] + coordinates_ens1 = coordinates[:, np.where(details["ensemble_membership"] == 1)] + coordinates_ens3 = coordinates[:, np.where(details["ensemble_membership"] == 3)] assert_allclose( coordinates_ens1, coordinates_ens3, @@ -1075,9 +1027,7 @@ def test_dimensionality_reduction_specified_dimension(self, ens1, ens2): dimension = 3 coordinates, details = encore.reduce_dimensionality( [ens1, ens2], - method=encore.StochasticProximityEmbeddingNative( - dimension=dimension - ), + method=encore.StochasticProximityEmbeddingNative(dimension=dimension), ) assert_equal( coordinates.shape[0], diff --git a/testsuite/MDAnalysisTests/analysis/test_gnm.py b/testsuite/MDAnalysisTests/analysis/test_gnm.py index 19d5a00093..cee3ab33dc 100644 --- a/testsuite/MDAnalysisTests/analysis/test_gnm.py +++ b/testsuite/MDAnalysisTests/analysis/test_gnm.py @@ -179,9 +179,7 @@ def test_closeContactGNMAnalysis_weights_None(universe, client_GNMAnalysis): def test_closeContactGNMAnalysis_select_CA(universe, client_GNMAnalysis): # Issue #4924 fix the bug of CA selection - gnm = mda.analysis.gnm.closeContactGNMAnalysis( - universe, "name CA", weights=None - ) + gnm = mda.analysis.gnm.closeContactGNMAnalysis(universe, "name CA", weights=None) gnm.run(stop=2, **client_GNMAnalysis) result = gnm.results assert len(result.times) == 2 diff --git a/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py b/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py index 3a291050d4..9e854424fe 100644 --- a/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py +++ b/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py @@ -160,9 +160,7 @@ def test_local_screw_angles_plane_circle(): """ angdeg = np.arange(0, 360, 12, dtype=np.int32) angrad = np.deg2rad(angdeg, dtype=np.float64) - xyz = np.array( - [[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64 - ) + xyz = np.array([[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64) xyz[15, 1] = 0 # because np.sin(np.deg2rad(180)) = 1e-16 ?! screw = hel.local_screw_angles([1, 0, 0], [0, 1, 0], xyz) correct = np.zeros_like(angdeg) @@ -178,9 +176,7 @@ def test_local_screw_angles_ortho_circle(): """ angdeg = np.arange(0, 360, 12, dtype=np.int32) angrad = np.deg2rad(angdeg, dtype=np.float64) - xyz = np.array( - [[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64 - ) + xyz = np.array([[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64) xyz[15, 1] = 0 # because np.sin(np.deg2rad(180)) = 1e-16 ?! screw = hel.local_screw_angles([1, 0, 0], [0, 0, 1], xyz) correct = np.zeros_like(angdeg) @@ -246,9 +242,7 @@ def zigzag(): x x x x x """ n_atoms = 100 - u = mda.Universe.empty( - 100, atom_resindex=np.arange(n_atoms), trajectory=True - ) + u = mda.Universe.empty(100, atom_resindex=np.arange(n_atoms), trajectory=True) xyz = np.array( list( zip( @@ -307,9 +301,7 @@ def test_helix_analysis_zigzag(zigzag, ref_axis, screw_angles): origins = zigzag.atoms.positions[1:-1].copy() origins[:, 0] = 0 assert_almost_equal(properties["local_origins"], origins, decimal=4) - assert_almost_equal( - properties["local_screw_angles"], screw_angles * 49, decimal=4 - ) + assert_almost_equal(properties["local_screw_angles"], screw_angles * 49, decimal=4) def square_oct(n_rep=10): @@ -348,9 +340,7 @@ def test_helix_analysis_square_oct(): properties = hel.helix_analysis(u.atoms.positions, ref_axis=[0, 0, 1]) twist_trans = [102.76438, 32.235607] twists = ([90] * 2 + twist_trans + [45] * 6 + twist_trans[::-1]) * n_rep - assert_almost_equal( - properties["local_twists"], twists[: n_atoms - 3], decimal=4 - ) + assert_almost_equal(properties["local_twists"], twists[: n_atoms - 3], decimal=4) res_trans = [3.503159, 11.167775] res = ([4] * 2 + res_trans + [8] * 6 + res_trans[::-1]) * n_rep assert_almost_equal( @@ -418,9 +408,7 @@ def test_helix_analysis_square_oct(): ] * n_rep # not quite 0, comes out as 1.32e-06 - assert_almost_equal( - properties["local_screw_angles"], screw[:-2], decimal=3 - ) + assert_almost_equal(properties["local_screw_angles"], screw[:-2], decimal=3) class TestHELANAL(object): @@ -433,17 +421,13 @@ def psf_ca(self): @pytest.fixture() def helanal(self, psf_ca): - ha = hel.HELANAL( - psf_ca, select="resnum 161-187", flatten_single_helix=True - ) + ha = hel.HELANAL(psf_ca, select="resnum 161-187", flatten_single_helix=True) return ha.run(start=10, stop=80) def test_regression_summary(self, helanal): bends = helanal.results.summary["all_bends"] old_helanal = read_bending_matrix(HELANAL_BENDING_MATRIX_SUBSET) - assert_almost_equal( - np.triu(bends["mean"], 1), old_helanal["Mean"], decimal=1 - ) + assert_almost_equal(np.triu(bends["mean"], 1), old_helanal["Mean"], decimal=1) assert_almost_equal( np.triu(bends["sample_sd"], 1), old_helanal["SD"], decimal=1 ) @@ -470,9 +454,7 @@ def test_regression_values(self): calculated = ha.results[key][0] msg = "Mismatch between calculated and reference {}" - assert_almost_equal( - calculated, value, decimal=4, err_msg=msg.format(key) - ) + assert_almost_equal(calculated, value, decimal=4, err_msg=msg.format(key)) def test_multiple_selections(self, psf_ca): ha = hel.HELANAL( diff --git a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py index 97eeb6cc01..b3b3bd34f2 100644 --- a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py +++ b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py @@ -245,9 +245,7 @@ def actual_function_int(t): tau2 = 1 tau3 = 0.1 return ( - A1 * np.exp(-t / tau1) - + A2 * np.exp(-t / tau2) - + A3 * np.exp(-t / tau3) + A1 * np.exp(-t / tau1) + A2 * np.exp(-t / tau2) + A3 * np.exp(-t / tau3) ) hbond.solution["time"] = time = np.arange(0, 6.0, 0.01) @@ -321,9 +319,7 @@ def test_solve_before_run_VE(self, u, hydrogens, oxygens, nitrogens): hbond.solve() @mock.patch("MDAnalysis.coordinates.TRZ.TRZReader._read_frame") - def test_unslicable_traj_VE( - self, mock_read, u, hydrogens, oxygens, nitrogens - ): + def test_unslicable_traj_VE(self, mock_read, u, hydrogens, oxygens, nitrogens): mock_read.side_effect = TypeError with pytest.raises(ValueError): diff --git a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py index e1822b62fa..70b67e08df 100644 --- a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py +++ b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py @@ -248,9 +248,7 @@ def actual_function_int(t): tau2 = 1 tau3 = 0.1 return ( - A1 * np.exp(-t / tau1) - + A2 * np.exp(-t / tau2) - + A3 * np.exp(-t / tau3) + A1 * np.exp(-t / tau1) + A2 * np.exp(-t / tau2) + A3 * np.exp(-t / tau3) ) hbond.solution["time"] = time = np.arange(0, 6.0, 0.01) @@ -324,9 +322,7 @@ def test_solve_before_run_VE(self, u, hydrogens, oxygens, nitrogens): hbond.solve() @mock.patch("MDAnalysis.coordinates.TRZ.TRZReader._read_frame") - def test_unslicable_traj_VE( - self, mock_read, u, hydrogens, oxygens, nitrogens - ): + def test_unslicable_traj_VE(self, mock_read, u, hydrogens, oxygens, nitrogens): mock_read.side_effect = TypeError with pytest.raises(ValueError): diff --git a/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py b/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py index 2d70da9915..b25b89f35a 100644 --- a/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py +++ b/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py @@ -89,18 +89,10 @@ def test_hbond_analysis(self, h): "angle": {"mean": 158.9038039, "std": 12.0362826}, } - assert_allclose( - np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"] - ) - assert_allclose( - np.std(h.results.hbonds[:, 4]), reference["distance"]["std"] - ) - assert_allclose( - np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"] - ) - assert_allclose( - np.std(h.results.hbonds[:, 5]), reference["angle"]["std"] - ) + assert_allclose(np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"]) + assert_allclose(np.std(h.results.hbonds[:, 4]), reference["distance"]["std"]) + assert_allclose(np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"]) + assert_allclose(np.std(h.results.hbonds[:, 5]), reference["angle"]["std"]) def test_count_by_time(self, h): @@ -211,9 +203,7 @@ def universe(): @staticmethod @pytest.fixture(scope="class") def hydrogen_bonds(universe, client_HydrogenBondAnalysis): - h = HydrogenBondAnalysis( - universe, **TestHydrogenBondAnalysisIdeal.kwargs - ) + h = HydrogenBondAnalysis(universe, **TestHydrogenBondAnalysisIdeal.kwargs) h.run(**client_HydrogenBondAnalysis) return h @@ -289,9 +279,7 @@ def test_hydrogen_bond_lifetime(self, hydrogen_bonds): assert_array_equal(timeseries, [1, 0, 0]) def test_hydrogen_bond_lifetime_intermittency(self, hydrogen_bonds): - tau_timeseries, timeseries = hydrogen_bonds.lifetime( - tau_max=2, intermittency=1 - ) + tau_timeseries, timeseries = hydrogen_bonds.lifetime(tau_max=2, intermittency=1) assert_array_equal(timeseries, 1) def test_no_attr_hbonds(self, universe): @@ -300,9 +288,7 @@ def test_no_attr_hbonds(self, universe): with pytest.raises(NoDataError, match=".hbonds attribute is None"): hbonds.lifetime(tau_max=2, intermittency=1) - def test_logging_step_not_1( - self, universe, caplog, client_HydrogenBondAnalysis - ): + def test_logging_step_not_1(self, universe, caplog, client_HydrogenBondAnalysis): hbonds = HydrogenBondAnalysis(universe, **self.kwargs) # using step 2 hbonds.run(**client_HydrogenBondAnalysis, step=2) @@ -310,9 +296,7 @@ def test_logging_step_not_1( caplog.set_level(logging.WARNING) hbonds.lifetime(tau_max=2, intermittency=1) - warning = ( - "Autocorrelation: Hydrogen bonds were computed with " "step > 1." - ) + warning = "Autocorrelation: Hydrogen bonds were computed with " "step > 1." assert any(warning in rec.getMessage() for rec in caplog.records) @@ -387,9 +371,7 @@ def universe(): @staticmethod @pytest.fixture(scope="class") def hydrogen_bonds(universe, client_HydrogenBondAnalysis): - h = HydrogenBondAnalysis( - universe, **TestHydrogenBondAnalysisNoRes.kwargs - ) + h = HydrogenBondAnalysis(universe, **TestHydrogenBondAnalysisNoRes.kwargs) h.run(**client_HydrogenBondAnalysis) return h @@ -497,9 +479,7 @@ def test_between_all(self, universe, client_HydrogenBondAnalysis): [6, 7, 8], # protein-protein ] expected_hbond_distances = [2.5, 3.0, 3.0] - assert_array_equal( - hbonds.results.hbonds[:, 1:4], expected_hbond_indices - ) + assert_array_equal(hbonds.results.hbonds[:, 1:4], expected_hbond_indices) assert_allclose(hbonds.results.hbonds[:, 4], expected_hbond_distances) def test_between_PW(self, universe, client_HydrogenBondAnalysis): @@ -512,9 +492,7 @@ def test_between_PW(self, universe, client_HydrogenBondAnalysis): # indices of [donor, hydrogen, acceptor] for each hydrogen bond expected_hbond_indices = [[3, 4, 6]] # protein-water expected_hbond_distances = [3.0] - assert_array_equal( - hbonds.results.hbonds[:, 1:4], expected_hbond_indices - ) + assert_array_equal(hbonds.results.hbonds[:, 1:4], expected_hbond_indices) assert_allclose(hbonds.results.hbonds[:, 4], expected_hbond_distances) def test_between_PW_PP(self, universe, client_HydrogenBondAnalysis): @@ -536,9 +514,7 @@ def test_between_PW_PP(self, universe, client_HydrogenBondAnalysis): [6, 7, 8], # protein-protein ] expected_hbond_distances = [3.0, 3.0] - assert_array_equal( - hbonds.results.hbonds[:, 1:4], expected_hbond_indices - ) + assert_array_equal(hbonds.results.hbonds[:, 1:4], expected_hbond_indices) assert_allclose(hbonds.results.hbonds[:, 4], expected_hbond_distances) @@ -629,9 +605,7 @@ def h(self, universe): def test_guess_hydrogens(self, h): - ref_hydrogens = ( - "(resname TIP3 and name H1) or (resname TIP3 and name H2)" - ) + ref_hydrogens = "(resname TIP3 and name H1) or (resname TIP3 and name H2)" hydrogens = h.guess_hydrogens(select="all") assert hydrogens == ref_hydrogens @@ -689,18 +663,10 @@ def test_hbond_analysis(self, h): "angle": {"mean": 157.07768079, "std": 9.72636682}, } - assert_allclose( - np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"] - ) - assert_allclose( - np.std(h.results.hbonds[:, 4]), reference["distance"]["std"] - ) - assert_allclose( - np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"] - ) - assert_allclose( - np.std(h.results.hbonds[:, 5]), reference["angle"]["std"] - ) + assert_allclose(np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"]) + assert_allclose(np.std(h.results.hbonds[:, 4]), reference["distance"]["std"]) + assert_allclose(np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"]) + assert_allclose(np.std(h.results.hbonds[:, 5]), reference["angle"]["std"]) def test_count_by_time(self, h): diff --git a/testsuite/MDAnalysisTests/analysis/test_leaflet.py b/testsuite/MDAnalysisTests/analysis/test_leaflet.py index e968bbf8c9..0760be0f95 100644 --- a/testsuite/MDAnalysisTests/analysis/test_leaflet.py +++ b/testsuite/MDAnalysisTests/analysis/test_leaflet.py @@ -61,10 +61,7 @@ def test_leaflet_finder(self, universe, lipid_heads): lfls = LeafletFinder(universe, lipid_heads, pbc=True) top_heads, bottom_heads = lfls.groups() # Make top be... on top. - if ( - top_heads.center_of_geometry()[2] - < bottom_heads.center_of_geometry()[2] - ): + if top_heads.center_of_geometry()[2] < bottom_heads.center_of_geometry()[2]: top_heads, bottom_heads = (bottom_heads, top_heads) assert_equal( top_heads.indices, @@ -99,9 +96,7 @@ def test_pbc_on_off_difference(self, universe, lipid_heads): import networkx lfls_pbc_on = LeafletFinder(universe, lipid_heads, cutoff=7, pbc=True) - lfls_pbc_off = LeafletFinder( - universe, lipid_heads, cutoff=7, pbc=False - ) + lfls_pbc_off = LeafletFinder(universe, lipid_heads, cutoff=7, pbc=False) pbc_on_graph = lfls_pbc_on.graph pbc_off_graph = lfls_pbc_off.graph diff_graph = networkx.difference(pbc_on_graph, pbc_off_graph) @@ -189,13 +184,8 @@ def test_write_selection(self, universe, lipid_heads, tmpdir): ] ) - assert ( - self.lines2one(open("leaflet.vmd").readlines()) - == expected_output - ) + assert self.lines2one(open("leaflet.vmd").readlines()) == expected_output def test_component_index_is_not_none(self, universe, lipid_heads): lfls_ag = LeafletFinder(universe, lipid_heads, cutoff=15.0, pbc=True) - assert_almost_equal( - len(lfls_ag.groups(component_index=0)), 180, decimal=4 - ) + assert_almost_equal(len(lfls_ag.groups(component_index=0)), 180, decimal=4) diff --git a/testsuite/MDAnalysisTests/analysis/test_lineardensity.py b/testsuite/MDAnalysisTests/analysis/test_lineardensity.py index f775e6073a..67ea3f67aa 100644 --- a/testsuite/MDAnalysisTests/analysis/test_lineardensity.py +++ b/testsuite/MDAnalysisTests/analysis/test_lineardensity.py @@ -90,16 +90,12 @@ def test_invalid_grouping(client_LinearDensity): ) # test data for grouping='residues' -expected_masses_residues = np.array( - [18.0154, 18.0154, 18.0154, 18.0154, 18.0154] -) +expected_masses_residues = np.array([18.0154, 18.0154, 18.0154, 18.0154, 18.0154]) expected_charges_residues = np.array([0, 0, 0, 0, 0]) expected_xmass_residues = np.array( [0.0, 0.0, 0.0, 0.00717967, 0.00478644, 0.0, 0.0, 0.0, 0.0, 0.0] ) -expected_xcharge_residues = np.array( - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] -) +expected_xcharge_residues = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # test data for grouping='segments' expected_masses_segments = np.array([90.0770]) @@ -107,14 +103,10 @@ def test_invalid_grouping(client_LinearDensity): expected_xmass_segments = np.array( [0.0, 0.0, 0.0, 0.01196611, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ) -expected_xcharge_segments = np.array( - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] -) +expected_xcharge_segments = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # test data for grouping='fragments' -expected_masses_fragments = np.array( - [18.0154, 18.0154, 18.0154, 18.0154, 18.0154] -) +expected_masses_fragments = np.array([18.0154, 18.0154, 18.0154, 18.0154, 18.0154]) expected_charges_fragments = np.array([0, 0, 0, 0, 0]) expected_xmass_fragments = np.array( [0.0, 0.0, 0.0, 0.00717967, 0.00478644, 0.0, 0.0, 0.0, 0.0, 0.0] @@ -168,9 +160,7 @@ def test_lineardensity( universe = mda.Universe(waterPSF, waterDCD) sel_string = "all" selection = universe.select_atoms(sel_string) - ld = LinearDensity(selection, grouping, binsize=5).run( - **client_LinearDensity - ) + ld = LinearDensity(selection, grouping, binsize=5).run(**client_LinearDensity) assert_allclose(ld.masses, expected_masses) assert_allclose(ld.charges, expected_charges) # rtol changed here due to floating point imprecision @@ -241,13 +231,9 @@ def test_old_name_deprecations(): assert_allclose(ld.results.x.pos, ld.results.x.mass_density) assert_allclose(ld.results.x.pos_std, ld.results.x.mass_density_stddev) assert_allclose(ld.results.x.char, ld.results.x.charge_density) - assert_allclose( - ld.results.x.char_std, ld.results.x.charge_density_stddev - ) + assert_allclose(ld.results.x.char_std, ld.results.x.charge_density_stddev) for key in testdict.keys(): - assert_allclose( - ld.results["x"][key], ld.results["x"][testdict[key]] - ) + assert_allclose(ld.results["x"][key], ld.results["x"][testdict[key]]) # Check that no DeprecationWarning is raised with new attributes with no_deprecated_call(): @@ -271,16 +257,10 @@ def test_parallel_analysis(testing_Universe): ld1 = LinearDensity(selection1, binsize=1).run() ld2 = LinearDensity(selection2, binsize=1).run() ld_whole = LinearDensity(selection_whole, binsize=1).run() - with pytest.warns( - DeprecationWarning, match="`_add_other_results` is deprecated!" - ): + with pytest.warns(DeprecationWarning, match="`_add_other_results` is deprecated!"): ld1._add_other_results(ld2) - assert_allclose( - ld1.results.z.mass_density, ld_whole.results.z.mass_density - ) - assert_allclose( - ld1.results.x.mass_density, ld_whole.results.x.mass_density - ) + assert_allclose(ld1.results.z.mass_density, ld_whole.results.z.mass_density) + assert_allclose(ld1.results.x.mass_density, ld_whole.results.x.mass_density) def test_class_is_parallelizable(): @@ -291,11 +271,8 @@ def test_class_is_parallelizable(): def test_supported_backends(): - assert ( - mda.analysis.lineardensity.LinearDensity.get_supported_backends() - == ( - "serial", - "multiprocessing", - "dask", - ) + assert mda.analysis.lineardensity.LinearDensity.get_supported_backends() == ( + "serial", + "multiprocessing", + "dask", ) diff --git a/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py b/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py index 61577599a0..140dba89b1 100644 --- a/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py +++ b/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py @@ -234,8 +234,6 @@ def test_hydroxyl(u, seg, i, expected_value): (8, 9, 10, "RNAA", "RNAA", "RNAA", 34.50106), ), ) -def test_pseudo_dihe_baseflip( - u, bp1, bp2, i, seg1, seg2, seg3, expected_value -): +def test_pseudo_dihe_baseflip(u, bp1, bp2, i, seg1, seg2, seg3, expected_value): val = nuclinfo.pseudo_dihe_baseflip(u, bp1, bp2, i, seg1, seg2, seg3) assert_almost_equal(val, expected_value, decimal=3) diff --git a/testsuite/MDAnalysisTests/analysis/test_pca.py b/testsuite/MDAnalysisTests/analysis/test_pca.py index 663aa5e68f..b0400e5dea 100644 --- a/testsuite/MDAnalysisTests/analysis/test_pca.py +++ b/testsuite/MDAnalysisTests/analysis/test_pca.py @@ -99,17 +99,13 @@ def test_cum_var(pca): def test_pcs(pca): - assert_equal( - pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3) - ) + assert_equal(pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3)) def test_pcs_n_components(u): pca = PCA(u, select=SELECTION).run() assert_equal(pca.n_components, pca._n_atoms * 3) - assert_equal( - pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3) - ) + assert_equal(pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3)) pca.n_components = 10 assert_equal(pca.n_components, 10) assert_equal(pca.results.p_components.shape, (pca._n_atoms * 3, 10)) @@ -191,9 +187,7 @@ def test_project_none_anchor(u, pca): group = u.select_atoms("resnum 1") with pytest.raises(ValueError) as exc: func = pca.project_single_frame(0, group=group, anchor=None) - assert ("'anchor' cannot be 'None'" + " if 'group' is not 'None'") in str( - exc.value - ) + assert ("'anchor' cannot be 'None'" + " if 'group' is not 'None'") in str(exc.value) def test_project_more_anchor(u, pca): @@ -207,9 +201,7 @@ def test_project_less_anchor(u, pca): group = u.select_atoms("all") with pytest.raises(ValueError) as exc: project = pca.project_single_frame(0, group=group, anchor="name CB") - assert ("Some residues in 'group'" + " do not have an 'anchor'") in str( - exc.value - ) + assert ("Some residues in 'group'" + " do not have an 'anchor'") in str(exc.value) def test_project_invalid_anchor(u): @@ -275,9 +267,7 @@ def test_project_extrapolate_translation(u_fresh): project = pca.project_single_frame(0, group=group, anchor="name CA") distances_original = mda.lib.distances.self_distance_array(group.positions) - distances_new = mda.lib.distances.self_distance_array( - project(group).positions - ) + distances_new = mda.lib.distances.self_distance_array(project(group).positions) assert_allclose(distances_original, distances_new, rtol=1e-05) @@ -386,9 +376,7 @@ def test_compare_wrong_class(u, pca, method): assert "must be another PCA class" in str(exc.value) -@pytest.mark.parametrize( - "attr", ("p_components", "variance", "cumulated_variance") -) +@pytest.mark.parametrize("attr", ("p_components", "variance", "cumulated_variance")) def test_pca_attr_warning(u, attr): pca = PCA(u, select=SELECTION).run(stop=2) wmsg = f"The `{attr}` attribute was deprecated in MDAnalysis 2.0.0" diff --git a/testsuite/MDAnalysisTests/analysis/test_persistencelength.py b/testsuite/MDAnalysisTests/analysis/test_persistencelength.py index 3cbee2952c..68dc7bcb58 100644 --- a/testsuite/MDAnalysisTests/analysis/test_persistencelength.py +++ b/testsuite/MDAnalysisTests/analysis/test_persistencelength.py @@ -68,9 +68,7 @@ def test_lb(self, p_run): def test_fit(self, p_run): assert_almost_equal(p_run.results.lp, 6.504, 3) - assert len(p_run.results.fit) == len( - p_run.results.bond_autocorrelation - ) + assert len(p_run.results.fit) == len(p_run.results.bond_autocorrelation) def test_raise_NoDataError(self, p): # Ensure that a NoDataError is raised if perform_fit() diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index aa14071069..505e446192 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -97,9 +97,7 @@ def test_exclusion(sels): assert rdf.results.count.sum() == 4 -@pytest.mark.parametrize( - "attr, count", [("residue", 8), ("segment", 0), ("chain", 8)] -) +@pytest.mark.parametrize("attr, count", [("residue", 8), ("segment", 0), ("chain", 8)]) def test_ignore_same_residues(sels, attr, count): # should see two distances with 4 counts each s1, s2 = sels diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index 3faac69ce3..ad88a839cd 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -120,9 +120,7 @@ def test_density(u, sels, density, value): assert_almost_equal(max(rdf.results.rdf[0][0][0]), value) if not density: s1 = u.select_atoms("name ZND and resid 289") - s2 = u.select_atoms( - "name OD1 and resid 51 and sphzone 5.0 (resid 289)" - ) + s2 = u.select_atoms("name OD1 and resid 51 and sphzone 5.0 (resid 289)") rdf_ref = InterRDF(s1, s2).run() assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) @@ -145,9 +143,7 @@ def test_norm(u, sels, norm, value): assert_allclose(max(rdf.results.rdf[0][0][0]), value) if norm == "rdf": s1 = u.select_atoms("name ZND and resid 289") - s2 = u.select_atoms( - "name OD1 and resid 51 and sphzone 5.0 (resid 289)" - ) + s2 = u.select_atoms("name OD1 and resid 51 and sphzone 5.0 (resid 289)") rdf_ref = InterRDF(s1, s2).run() assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) diff --git a/testsuite/MDAnalysisTests/analysis/test_results.py b/testsuite/MDAnalysisTests/analysis/test_results.py index adfbc4b506..61773c1a47 100644 --- a/testsuite/MDAnalysisTests/analysis/test_results.py +++ b/testsuite/MDAnalysisTests/analysis/test_results.py @@ -156,9 +156,7 @@ def merger(self): @pytest.mark.parametrize("n", [1, 2, 5, 14]) def test_all_results(self, results_0, results_1, merger, n): - objects = [ - obj for obj, _ in zip(cycle([results_0, results_1]), range(n)) - ] + objects = [obj for obj, _ in zip(cycle([results_0, results_1]), range(n))] arr = [i for _, i in zip(range(n), cycle([0, 1]))] answers = { @@ -181,9 +179,7 @@ def test_missing_aggregator(self, results_0, results_1, merger): original_float_lookup = merger._lookup.get("float") merger._lookup["float"] = None - with pytest.raises( - ValueError, match="No aggregation function for key='float'" - ): + with pytest.raises(ValueError, match="No aggregation function for key='float'"): merger.merge([results_0, results_1], require_all_aggregators=True) merger._lookup["float"] = original_float_lookup diff --git a/testsuite/MDAnalysisTests/analysis/test_rms.py b/testsuite/MDAnalysisTests/analysis/test_rms.py index f39baa68f1..e1feb883e5 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rms.py +++ b/testsuite/MDAnalysisTests/analysis/test_rms.py @@ -72,8 +72,7 @@ def p_last(self, u2): def test_p_frames(self, p_first, p_last): # check that these fixtures are really different assert ( - p_first.universe.trajectory.ts.frame - != p_last.universe.trajectory.ts.frame + p_first.universe.trajectory.ts.frame != p_last.universe.trajectory.ts.frame ) assert not np.allclose(p_first.positions, p_last.positions) @@ -117,9 +116,7 @@ def test_weights_and_superposition_1(self, u): weights=weights, superposition=True, ) - firstCoords = rms.rmsd( - u.trajectory[0], u.trajectory[1], superposition=True - ) + firstCoords = rms.rmsd(u.trajectory[0], u.trajectory[1], superposition=True) assert_almost_equal(weighted, firstCoords, decimal=5) def test_weights_and_superposition_2(self, u): @@ -219,9 +216,7 @@ def test_rmsd_frames(self, universe, correct_values, client_RMSD): err_msg="error: rmsd profile should match" + "test values", ) - def test_rmsd_unicode_selection( - self, universe, correct_values, client_RMSD - ): + def test_rmsd_unicode_selection(self, universe, correct_values, client_RMSD): RMSD = MDAnalysis.analysis.rms.RMSD(universe, select="name CA") RMSD.run(step=49, **client_RMSD) assert_almost_equal( @@ -233,9 +228,9 @@ def test_rmsd_unicode_selection( def test_rmsd_atomgroup_selections(self, universe, client_RMSD): # see Issue #1684 - R1 = MDAnalysis.analysis.rms.RMSD( - universe.atoms, select="resid 1-30" - ).run(**client_RMSD) + R1 = MDAnalysis.analysis.rms.RMSD(universe.atoms, select="resid 1-30").run( + **client_RMSD + ) R2 = MDAnalysis.analysis.rms.RMSD( universe.atoms.select_atoms("name CA"), select="resid 1-30" ).run(**client_RMSD) @@ -295,13 +290,11 @@ def test_weights_mass_is_mass_weighted(self, universe, client_RMSD): "and universe.atoms.masses", ) - def test_custom_weighted_list( - self, universe, correct_values_mass, client_RMSD - ): + def test_custom_weighted_list(self, universe, correct_values_mass, client_RMSD): weights = universe.atoms.masses - RMSD = MDAnalysis.analysis.rms.RMSD( - universe, weights=list(weights) - ).run(step=49, **client_RMSD) + RMSD = MDAnalysis.analysis.rms.RMSD(universe, weights=list(weights)).run( + step=49, **client_RMSD + ) assert_almost_equal( RMSD.results.rmsd, correct_values_mass, @@ -361,9 +354,7 @@ def test_rmsd_mismatched_weights_raises_ValueError(self, universe): universe, weights=universe.atoms.masses[:-1] ) - def test_rmsd_misuse_weights_for_groupselection_raises_TypeError( - self, universe - ): + def test_rmsd_misuse_weights_for_groupselection_raises_TypeError(self, universe): with pytest.raises(TypeError): RMSD = MDAnalysis.analysis.rms.RMSD( universe, @@ -391,9 +382,7 @@ def test_rmsd_list_of_weights_wrong_length(self, universe): weights_groupselections=[None], ) - def test_rmsd_group_selections( - self, universe, correct_values_group, client_RMSD - ): + def test_rmsd_group_selections(self, universe, correct_values_group, client_RMSD): RMSD = MDAnalysis.analysis.rms.RMSD( universe, groupselections=["backbone", "name CA"] ).run(step=49, **client_RMSD) @@ -519,9 +508,7 @@ def test_rmsf_identical_frames(self, universe, tmpdir, client_RMSF): ) def test_rmsf_attr_warning(self, universe, client_RMSF): - rmsfs = rms.RMSF(universe.select_atoms("name CA")).run( - stop=2, **client_RMSF - ) + rmsfs = rms.RMSF(universe.select_atoms("name CA")).run(stop=2, **client_RMSF) wmsg = "The `rmsf` attribute was deprecated in MDAnalysis 2.0.0" with pytest.warns(DeprecationWarning, match=wmsg): diff --git a/testsuite/MDAnalysisTests/analysis/test_wbridge.py b/testsuite/MDAnalysisTests/analysis/test_wbridge.py index 2b53d2f1d3..e364430694 100644 --- a/testsuite/MDAnalysisTests/analysis/test_wbridge.py +++ b/testsuite/MDAnalysisTests/analysis/test_wbridge.py @@ -287,9 +287,7 @@ def wb_multiframe(): wb.results.network.append( { (0, None, 3, 2, 2.0, 180.0): { - (4, 2, 5, None, 2.0, 180.0): { - (5, None, 11, 12, 2.0, 180.0): None - } + (4, 2, 5, None, 2.0, 180.0): {(5, None, 11, 12, 2.0, 180.0): None} } } ) @@ -691,18 +689,10 @@ def test_timeseries_wba(self, universe_branch): wb.run(verbose=False) timeseries = sorted(wb.results.timeseries[0]) - assert_equal( - timeseries[0][:4], (0, 2, ("ALA", 1, "O"), ("SOL", 2, "HW1")) - ) - assert_equal( - timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW")) - ) - assert_equal( - timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O")) - ) - assert_equal( - timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O")) - ) + assert_equal(timeseries[0][:4], (0, 2, ("ALA", 1, "O"), ("SOL", 2, "HW1"))) + assert_equal(timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW"))) + assert_equal(timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O"))) + assert_equal(timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O"))) def test_timeseries_hba(self, universe_branch): """Test if the time series data is correctly generated in hydrogen bond analysis format""" @@ -716,18 +706,10 @@ def test_timeseries_hba(self, universe_branch): wb.run(verbose=False) timeseries = sorted(wb.results.timeseries[0]) - assert_equal( - timeseries[0][:4], (2, 0, ("SOL", 2, "HW1"), ("ALA", 1, "O")) - ) - assert_equal( - timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW")) - ) - assert_equal( - timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O")) - ) - assert_equal( - timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O")) - ) + assert_equal(timeseries[0][:4], (2, 0, ("SOL", 2, "HW1"), ("ALA", 1, "O"))) + assert_equal(timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW"))) + assert_equal(timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O"))) + assert_equal(timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O"))) @pytest.mark.parametrize("distance_type", ["hydrogen", "heavy"]) def test_acceptor_12water_accepter(self, universe_AWA_AWWA, distance_type): @@ -768,9 +750,7 @@ def test_count_by_type_single_link(self, universe_DWA): universe_DWA, "protein and (resid 1)", "protein and (resid 4)" ) wb.run(verbose=False) - assert_equal( - wb.count_by_type(), [(1, 4, "ALA", 1, "H", "ALA", 4, "O", 1.0)] - ) + assert_equal(wb.count_by_type(), [(1, 4, "ALA", 1, "H", "ALA", 4, "O", 1.0)]) def test_count_by_type_multiple_link(self, universe_AWA_AWWA): """ @@ -812,12 +792,10 @@ def test_count_by_type_filter(self, wb_multiframe): """ def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( - current[0] - ) - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( - current[-1] - ) + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ + -1 + ] sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -856,12 +834,10 @@ def test_count_by_type_merge(self, wb_multiframe): """ def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( - current[0] - ) - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( - current[-1] - ) + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ + -1 + ] sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -891,12 +867,10 @@ def test_count_by_type_order(self, wb_multiframe): """ def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( - current[0] - ) - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( - current[-1] - ) + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ + -1 + ] sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -932,9 +906,7 @@ def test_count_by_time(self, wb_multiframe): This test tests if count_by_times() works. :return: """ - assert_equal( - wb_multiframe.count_by_time(), [(0, 1), (1, 1), (2, 1), (3, 1)] - ) + assert_equal(wb_multiframe.count_by_time(), [(0, 1), (1, 1), (2, 1), (3, 1)]) def test_count_by_time_weight(self, universe_AWA_AWWA): """ @@ -951,12 +923,10 @@ def test_count_by_time_weight(self, universe_AWA_AWWA): wb.run(verbose=False) def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( - current[0] - ) - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( - current[-1] - ) + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ + -1 + ] sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -1022,9 +992,7 @@ def test_timesteps_by_type(self, wb_multiframe): """Test the timesteps_by_type function""" timesteps = sorted(wb_multiframe.timesteps_by_type()) - assert_array_equal( - timesteps[3], [1, 12, "ALA", 1, "H", "ALA", 6, "O", 0, 2] - ) + assert_array_equal(timesteps[3], [1, 12, "ALA", 1, "H", "ALA", 6, "O", 0, 2]) def test_duplicate_water(self): """A case #3119 where diff --git a/testsuite/MDAnalysisTests/auxiliary/base.py b/testsuite/MDAnalysisTests/auxiliary/base.py index e3e82a0161..03daaebe02 100644 --- a/testsuite/MDAnalysisTests/auxiliary/base.py +++ b/testsuite/MDAnalysisTests/auxiliary/base.py @@ -116,9 +116,7 @@ def reference_timestep(dt=1, offset=0): # for 'average': use low frequenct timestep, only step 2 within 0ps cutoff self.lowf_cutoff_average_rep = self.format_data([2, 2 * 2, 2**2]) # for 'closest': use offset timestep; no timestep within 0ps cutoff - self.offset_cutoff_closest_rep = self.format_data( - [np.nan, np.nan, np.nan] - ) + self.offset_cutoff_closest_rep = self.format_data([np.nan, np.nan, np.nan]) ## testing selection of time/data. Overload for each auxilairy format ## as appropraite. @@ -150,9 +148,7 @@ def test_dt(self, ref, reader): assert reader.dt == ref.dt, "dt does not match" def test_initial_time(self, ref, reader): - assert ( - reader.initial_time == ref.initial_time - ), "initial time does not match" + assert reader.initial_time == ref.initial_time, "initial time does not match" def test_first_step(self, ref, reader): # on first loading we should start at step 0 @@ -327,8 +323,7 @@ def test_represent_as_average_with_cutoff(self, ref, reader): assert_almost_equal( ts.aux.test, ref.lowf_cutoff_average_rep, - err_msg="Representative value does not match when " - "applying cutoff", + err_msg="Representative value does not match when " "applying cutoff", ) def test_read_offset_timestep(self, ref, reader): @@ -352,8 +347,7 @@ def test_represent_as_closest_with_cutoff(self, ref, reader): assert_almost_equal( ts.aux.test, ref.offset_cutoff_closest_rep, - err_msg="Representative value does not match when " - "applying cutoff", + err_msg="Representative value does not match when " "applying cutoff", ) def test_read_higher_freq_timestep(self, ref, reader): @@ -405,8 +399,7 @@ def test_auxiliary_read_ts_rewind(self, ref_universe): assert_equal( aux_info_0, aux_info_0_rewind, - "aux info was retrieved incorrectly " - "after reading the last step", + "aux info was retrieved incorrectly " "after reading the last step", ) def test_get_description(self, ref, reader): @@ -419,9 +412,7 @@ def test_get_description(self, ref, reader): def test_load_from_description(self, reader): description = reader.get_description() new = mda.auxiliary.core.auxreader(**description) - assert ( - new == reader - ), "AuxReader reloaded from description does not match" + assert new == reader, "AuxReader reloaded from description does not match" def test_step_to_frame_out_of_bounds(self, reader, ref): @@ -446,9 +437,7 @@ def test_step_to_frame_time_diff(self, reader, ref): # Test all 5 frames for idx in range(5): - frame, time_diff = reader.step_to_frame( - idx, ts, return_time_diff=True - ) + frame, time_diff = reader.step_to_frame(idx, ts, return_time_diff=True) assert frame == idx np.testing.assert_almost_equal(time_diff, idx * 0.1) diff --git a/testsuite/MDAnalysisTests/auxiliary/test_core.py b/testsuite/MDAnalysisTests/auxiliary/test_core.py index 8a630c6e48..b17637daaf 100644 --- a/testsuite/MDAnalysisTests/auxiliary/test_core.py +++ b/testsuite/MDAnalysisTests/auxiliary/test_core.py @@ -28,16 +28,12 @@ def test_get_auxreader_for_none(): - with pytest.raises( - ValueError, match="Must provide either auxdata or format" - ): + with pytest.raises(ValueError, match="Must provide either auxdata or format"): mda.auxiliary.core.get_auxreader_for() def test_get_auxreader_for_wrong_auxdata(): - with pytest.raises( - ValueError, match="Unknown auxiliary data format for auxdata:" - ): + with pytest.raises(ValueError, match="Unknown auxiliary data format for auxdata:"): mda.auxiliary.core.get_auxreader_for(auxdata="test.none") @@ -47,9 +43,7 @@ def test_get_auxreader_for_wrong_format(): def test_notimplemented_read_next_timestep(): - with pytest.raises( - NotImplementedError, match="BUG: Override " "_read_next_step()" - ): + with pytest.raises(NotImplementedError, match="BUG: Override " "_read_next_step()"): reader = mda.auxiliary.base.AuxReader() @@ -59,8 +53,6 @@ def _read_next_step(self): def test_notimplemented_memory_usage(): - with pytest.raises( - NotImplementedError, match="BUG: Override " "_memory_usage()" - ): + with pytest.raises(NotImplementedError, match="BUG: Override " "_memory_usage()"): reader = No_Memory_Usage() reader._memory_usage() diff --git a/testsuite/MDAnalysisTests/auxiliary/test_edr.py b/testsuite/MDAnalysisTests/auxiliary/test_edr.py index 8668c8a056..9da63cf2a7 100644 --- a/testsuite/MDAnalysisTests/auxiliary/test_edr.py +++ b/testsuite/MDAnalysisTests/auxiliary/test_edr.py @@ -105,9 +105,7 @@ def __init__(self): def reference_auxstep(i): # create a reference AuxStep for step i t_init = self.initial_time - auxstep = mda.auxiliary.EDR.EDRStep( - dt=self.dt, initial_time=t_init - ) + auxstep = mda.auxiliary.EDR.EDRStep(dt=self.dt, initial_time=t_init) auxstep.step = i auxstep._data = get_auxstep_data(i) return auxstep @@ -228,9 +226,7 @@ def reader(ref): data = reader.data_dict[term] reader_unit = reader.unit_dict[term] try: - reader.data_dict[term] = units.convert( - data, reader_unit, ref_unit - ) + reader.data_dict[term] = units.convert(data, reader_unit, ref_unit) except ValueError: continue # some units not supported yet reader.rewind() @@ -241,9 +237,7 @@ def test_time_non_constant_dt(self, reader): reader.time_selector = None with pytest.raises( ValueError, - match="If dt is not constant, " - "must have a valid time " - "selector", + match="If dt is not constant, " "must have a valid time " "selector", ): reader.time @@ -269,9 +263,7 @@ def test_step_to_frame_time_diff(self, reader, ref): # Test all 4 frames for idx in range(4): - frame, time_diff = reader.step_to_frame( - idx, ts, return_time_diff=True - ) + frame, time_diff = reader.step_to_frame(idx, ts, return_time_diff=True) assert frame == idx assert_allclose(time_diff, idx * 0.002) @@ -334,8 +326,7 @@ def test_represent_as_average_with_cutoff(self, ref, reader): assert_allclose( ts.aux.test["Bond"], ref.lowf_cutoff_average_rep, - err_msg="Representative value does not match when " - "applying cutoff", + err_msg="Representative value does not match when " "applying cutoff", ) # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 @@ -363,9 +354,7 @@ def test_add_term_list_custom_names_from_file(self, ref, ref_universe): assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def test_add_term_list_custom_names_from_reader( - self, ref_universe, reader - ): + def test_add_term_list_custom_names_from_reader(self, ref_universe, reader): ref_universe.trajectory.add_auxiliary( {"bond": "Bond", "temp": "Temperature"}, reader ) @@ -374,24 +363,18 @@ def test_add_term_list_custom_names_from_reader( assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def test_raise_error_if_auxname_already_assigned( - self, ref_universe, reader - ): + def test_raise_error_if_auxname_already_assigned(self, ref_universe, reader): with pytest.raises(ValueError, match="Auxiliary data with name"): ref_universe.trajectory.add_auxiliary("test", reader, "Bond") # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_add_single_term_custom_name_from_file(self, ref, ref_universe): - ref_universe.trajectory.add_auxiliary( - {"temp": "Temperature"}, ref.testdata - ) + ref_universe.trajectory.add_auxiliary({"temp": "Temperature"}, ref.testdata) ref_dict = get_auxstep_data(0) assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def test_add_single_term_custom_name_from_reader( - self, ref_universe, reader - ): + def test_add_single_term_custom_name_from_reader(self, ref_universe, reader): ref_universe.trajectory.add_auxiliary({"temp": "Temperature"}, reader) ref_dict = get_auxstep_data(0) assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] @@ -412,9 +395,7 @@ def test_terms_update_on_iter(self, ref_universe, reader): # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_invalid_data_selector(self, ref, ref_universe): with pytest.raises(KeyError, match="'Nonsense' is not a key"): - ref_universe.trajectory.add_auxiliary( - {"something": "Nonsense"}, AUX_EDR - ) + ref_universe.trajectory.add_auxiliary({"something": "Nonsense"}, AUX_EDR) def test_read_all_times(self, reader): all_times_expected = np.array([0.0, 0.02, 0.04, 0.06]) @@ -452,9 +433,7 @@ def test_get_data_invalid_selections(self, reader, get_data_input): # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_warning_when_space_in_aux_spec(self, ref_universe, reader): with pytest.warns(UserWarning, match="Auxiliary name"): - ref_universe.trajectory.add_auxiliary( - {"Pres. DC": "Pres. DC"}, reader - ) + ref_universe.trajectory.add_auxiliary({"Pres. DC": "Pres. DC"}, reader) # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_warn_too_much_memory_usage(self, ref_universe, reader): @@ -483,9 +462,7 @@ def test_units_are_converted_by_EDRReader(self, reader): # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_warning_when_unknown_unit(self, ref_universe, reader): with pytest.warns(UserWarning, match="Could not find"): - ref_universe.trajectory.add_auxiliary( - {"temp": "Temperature"}, reader - ) + ref_universe.trajectory.add_auxiliary({"temp": "Temperature"}, reader) def test_unit_conversion_is_optional(self, ref): reader = ref.reader( @@ -508,9 +485,7 @@ def test_unit_conversion_is_optional(self, ref): def test_single_frame_input_file(): """Previously, EDRReader could not handle EDR input files with only one frame. See Issue #3999.""" - reader = mda.auxiliary.EDR.EDRReader( - AUX_EDR_SINGLE_FRAME, convert_units=False - ) + reader = mda.auxiliary.EDR.EDRReader(AUX_EDR_SINGLE_FRAME, convert_units=False) ref_dict = get_auxstep_data(0) reader_data_dict = reader.auxstep.data assert ref_dict == reader_data_dict diff --git a/testsuite/MDAnalysisTests/auxiliary/test_xvg.py b/testsuite/MDAnalysisTests/auxiliary/test_xvg.py index 8926cabe32..2fdaf52405 100644 --- a/testsuite/MDAnalysisTests/auxiliary/test_xvg.py +++ b/testsuite/MDAnalysisTests/auxiliary/test_xvg.py @@ -75,9 +75,7 @@ def test_select_time_none(self, step): assert st is None def test_select_time_invalid_index(self, step): - with pytest.raises( - ValueError, match="Time selector must be single index" - ): + with pytest.raises(ValueError, match="Time selector must be single index"): step._select_time([0]) def test_select_data_none(self, step): @@ -170,9 +168,7 @@ def reader(ref): def test_get_auxreader_for(self, ref, reader): # Default reader of .xvg files is intead XVGReader, not XVGFileReader # so test specifying format - reader = mda.auxiliary.core.get_auxreader_for( - ref.testdata, format=ref.format - ) + reader = mda.auxiliary.core.get_auxreader_for(ref.testdata, format=ref.format) assert reader == ref.reader def test_reopen(self, reader): diff --git a/testsuite/MDAnalysisTests/converters/test_base.py b/testsuite/MDAnalysisTests/converters/test_base.py index a8bebca0c3..6d6f9f4d33 100644 --- a/testsuite/MDAnalysisTests/converters/test_base.py +++ b/testsuite/MDAnalysisTests/converters/test_base.py @@ -41,9 +41,7 @@ class DerivedConverter(ConverterBase): pass assert issubclass(DerivedConverter, ConverterBase) - assert not issubclass( - DerivedConverter, MDAnalysis.converters.base.ConverterBase - ) + assert not issubclass(DerivedConverter, MDAnalysis.converters.base.ConverterBase) def test_converters_converterbase_no_warning(): diff --git a/testsuite/MDAnalysisTests/converters/test_openmm_parser.py b/testsuite/MDAnalysisTests/converters/test_openmm_parser.py index 7188499fd8..c0762955b2 100644 --- a/testsuite/MDAnalysisTests/converters/test_openmm_parser.py +++ b/testsuite/MDAnalysisTests/converters/test_openmm_parser.py @@ -131,17 +131,13 @@ def test_masses(self, top): assert len(top.masses.values) == self.expected_n_atoms if self.expected_n_atoms: assert isinstance(top.masses.values, np.ndarray) - assert all( - isinstance(mass, np.float64) for mass in top.masses.values - ) + assert all(isinstance(mass, np.float64) for mass in top.masses.values) else: assert top.masses.values == [] def test_guessed_attributes(self, filename): u = mda.Universe(filename, topology_format="OPENMMTOPOLOGY") - u_guessed_attrs = [ - attr.attrname for attr in u._topology.guessed_attributes - ] + u_guessed_attrs = [attr.attrname for attr in u._topology.guessed_attributes] for attr in self.guessed_attrs: assert hasattr(u.atoms, attr) assert attr in u_guessed_attrs diff --git a/testsuite/MDAnalysisTests/converters/test_parmed.py b/testsuite/MDAnalysisTests/converters/test_parmed.py index 261d389603..1214fbea4a 100644 --- a/testsuite/MDAnalysisTests/converters/test_parmed.py +++ b/testsuite/MDAnalysisTests/converters/test_parmed.py @@ -57,9 +57,7 @@ def test_dimensions(self): self.ref.trajectory.ts.dimensions, rtol=0, atol=1e-3, - err_msg=( - "ParmEdReader failed to get unitcell dimensions " "from ParmEd" - ), + err_msg=("ParmEdReader failed to get unitcell dimensions " "from ParmEd"), ) def test_coordinates(self): @@ -79,9 +77,7 @@ def test_dimensions(self): self.ref.trajectory.ts.dimensions, rtol=0, atol=1e-3, - err_msg=( - "ParmEdReader failed to get unitcell dimensions " "from ParmEd" - ), + err_msg=("ParmEdReader failed to get unitcell dimensions " "from ParmEd"), ) def test_coordinates(self): @@ -203,9 +199,9 @@ def test_equivalent_atoms(self, ref, output): for attr in self.equal_atom_attrs: ra = getattr(r, attr) oa = getattr(o, attr) - assert ( - ra == oa - ), "atom {} not equal for atoms {} and {}".format(attr, r, o) + assert ra == oa, "atom {} not equal for atoms {} and {}".format( + attr, r, o + ) for attr in self.almost_equal_atom_attrs: ra = getattr(r, attr) @@ -215,10 +211,7 @@ def test_equivalent_atoms(self, ref, output): oa, rtol=0, atol=1e-2, - err_msg=( - f"atom {attr} not almost equal for atoms " - f"{r} and {o}" - ), + err_msg=(f"atom {attr} not almost equal for atoms " f"{r} and {o}"), ) @pytest.mark.parametrize("attr", ("bonds", "angles", "impropers", "cmaps")) diff --git a/testsuite/MDAnalysisTests/converters/test_parmed_parser.py b/testsuite/MDAnalysisTests/converters/test_parmed_parser.py index 1a11876fd4..e4a6e1c892 100644 --- a/testsuite/MDAnalysisTests/converters/test_parmed_parser.py +++ b/testsuite/MDAnalysisTests/converters/test_parmed_parser.py @@ -90,9 +90,7 @@ def test_bonds_total_counts(self, top, filename): assert len(top.bonds.values) == len(unique) def test_angles_total_counts(self, top, filename): - unique = set( - [(a.atom1.idx, a.atom2.idx, a.atom3.idx) for a in filename.angles] - ) + unique = set([(a.atom1.idx, a.atom2.idx, a.atom3.idx) for a in filename.angles]) assert len(top.angles.values) == len(unique) def test_dihedrals_total_counts(self, top, filename): @@ -129,9 +127,7 @@ def test_cmaps_total_counts(self, top, filename): assert len(top.cmaps.values) == len(unique) def test_ureybradleys_total_counts(self, top, filename): - unique = set( - [(a.atom1.idx, a.atom2.idx) for a in filename.urey_bradleys] - ) + unique = set([(a.atom1.idx, a.atom2.idx) for a in filename.urey_bradleys]) assert len(top.ureybradleys.values) == len(unique) def test_elements(self, top): @@ -217,9 +213,7 @@ def test_dihedrals_identity(self, top, value): vals = top.dihedrals.values assert value in vals or value[::-1] in vals - @pytest.mark.parametrize( - "value", ((17, 19, 21, 41, 43), (60, 62, 64, 79, 81)) - ) + @pytest.mark.parametrize("value", ((17, 19, 21, 41, 43), (60, 62, 64, 79, 81))) def test_cmaps_identity(self, top, value): vals = top.cmaps.values assert value in vals or value[::-1] in vals diff --git a/testsuite/MDAnalysisTests/converters/test_rdkit.py b/testsuite/MDAnalysisTests/converters/test_rdkit.py index 31bc390b4f..5dc77889a0 100644 --- a/testsuite/MDAnalysisTests/converters/test_rdkit.py +++ b/testsuite/MDAnalysisTests/converters/test_rdkit.py @@ -154,9 +154,7 @@ def test_compare_mol2reader(self): universe = mda.Universe(MolFactory.mol2_mol()) mol2 = mda.Universe(mol2_molecule) assert universe.trajectory.n_frames == mol2.trajectory.n_frames - assert_equal( - universe.trajectory.ts.positions, mol2.trajectory.ts.positions - ) + assert_equal(universe.trajectory.ts.positions, mol2.trajectory.ts.positions) @requires_rdkit @@ -195,9 +193,7 @@ def test_no_atoms_attr(self): @pytest.mark.parametrize("smi", ["[H]", "C", "O", "[He]"]) def test_single_atom_mol(self, smi): - u = mda.Universe.from_smiles( - smi, addHs=False, generate_coordinates=False - ) + u = mda.Universe.from_smiles(smi, addHs=False, generate_coordinates=False) mol = u.atoms.convert_to.rdkit(inferrer=None) assert mol.GetNumAtoms() == 1 assert mol.GetAtomWithIdx(0).GetSymbol() == smi.strip("[]") @@ -240,9 +236,7 @@ def test_monomer_info(self, pdb, sel_str, atom_index): assert mda_atom.segindex == mi.GetSegmentNumber() assert mda_atom.tempfactor == mi.GetTempFactor() - @pytest.mark.parametrize( - "rdmol", ["mol2_mol", "smiles_mol"], indirect=True - ) + @pytest.mark.parametrize("rdmol", ["mol2_mol", "smiles_mol"], indirect=True) def test_identical_topology(self, rdmol): u = mda.Universe(rdmol) umol = u.atoms.convert_to("RDKIT") @@ -251,9 +245,7 @@ def test_identical_topology(self, rdmol): assert_equal(u.atoms.bonds, u2.atoms.bonds) assert_equal(u.atoms.elements, u2.atoms.elements) assert_equal(u.atoms.names, u2.atoms.names) - assert_allclose( - u.atoms.positions, u2.atoms.positions, rtol=0, atol=1e-7 - ) + assert_allclose(u.atoms.positions, u2.atoms.positions, rtol=0, atol=1e-7) def test_raise_requires_elements(self): u = mda.Universe(mol2_molecule) @@ -269,9 +261,7 @@ def test_raise_requires_elements(self): def test_warn_guess_bonds(self): u = mda.Universe(PDB_helix) - with pytest.warns( - UserWarning, match="No `bonds` attribute in this AtomGroup" - ): + with pytest.warns(UserWarning, match="No `bonds` attribute in this AtomGroup"): u.atoms.convert_to("RDKIT") def test_bonds_outside_sel(self): @@ -292,9 +282,7 @@ def test_error_no_hydrogen_implicit(self, uo2): uo2.atoms.convert_to.rdkit(inferrer=None) def test_warning_no_hydrogen_force(self, uo2): - with pytest.warns( - UserWarning, match="Forcing to continue the conversion" - ): + with pytest.warns(UserWarning, match="Forcing to continue the conversion"): uo2.atoms.convert_to.rdkit(force=True) @pytest.mark.parametrize( @@ -443,30 +431,20 @@ def test_sanitize_fail_warning(self): def test_deprecation_max_iter(self, mol2, monkeypatch): mock = Mock(wraps=atomgroup_to_mol) - monkeypatch.setattr( - "MDAnalysis.converters.RDKit.atomgroup_to_mol", mock - ) - with pytest.warns( - DeprecationWarning, match="Using `max_iter` is deprecated" - ): + monkeypatch.setattr("MDAnalysis.converters.RDKit.atomgroup_to_mol", mock) + with pytest.warns(DeprecationWarning, match="Using `max_iter` is deprecated"): mol2.atoms.convert_to.rdkit(max_iter=2) assert mock.call_args.kwargs["inferrer"].max_iter == 2 def test_deprecation_NoImplicit(self, mol2, monkeypatch): mock = Mock(wraps=atomgroup_to_mol) - monkeypatch.setattr( - "MDAnalysis.converters.RDKit.atomgroup_to_mol", mock - ) - with pytest.warns( - DeprecationWarning, match="Using `NoImplicit` is deprecated" - ): + monkeypatch.setattr("MDAnalysis.converters.RDKit.atomgroup_to_mol", mock) + with pytest.warns(DeprecationWarning, match="Using `NoImplicit` is deprecated"): mol2.atoms.convert_to.rdkit(NoImplicit=False) assert mock.call_args.kwargs["inferrer"] is None def test_deprecation_atomgroup_to_mol_NoImplicit(self, mol2): - with pytest.warns( - DeprecationWarning, match="Using `NoImplicit` is deprecated" - ): + with pytest.warns(DeprecationWarning, match="Using `NoImplicit` is deprecated"): atomgroup_to_mol(mol2.atoms, NoImplicit=False) def test_atomgroup_to_mol_unexpected_kwargs(self, mol2): @@ -491,8 +469,7 @@ def test_sanitize_mol_error(self): mol = Chem.MolFromSmiles("[NH4]", sanitize=False) with pytest.raises( Chem.AtomValenceException, - match="Explicit valence for atom # 0 N, 4, is " - "greater than permitted", + match="Explicit valence for atom # 0 N, 4, is " "greater than permitted", ): sanitize_mol(mol) @@ -525,12 +502,8 @@ def assert_isomorphic_resonance_structure(self, mol, ref): """ isomorphic = mol.HasSubstructMatch(ref) if not isomorphic: - isomorphic = bool( - Chem.ResonanceMolSupplier(mol).GetSubstructMatch(ref) - ) - assert ( - isomorphic - ), f"{Chem.MolToSmiles(ref)} != {Chem.MolToSmiles(mol)}" + isomorphic = bool(Chem.ResonanceMolSupplier(mol).GetSubstructMatch(ref)) + assert isomorphic, f"{Chem.MolToSmiles(ref)} != {Chem.MolToSmiles(mol)}" @requires_rdkit @@ -793,9 +766,7 @@ def test_warn_conjugated_max_iter(self): smi = "[C-]C=CC=CC=CC=CC=CC=C[C-]" mol = Chem.MolFromSmiles(smi) inferrer = MDAnalysisInferrer(max_iter=2) - with pytest.warns( - UserWarning, match="reasonable number of iterations" - ): + with pytest.warns(UserWarning, match="reasonable number of iterations"): inferrer._rebuild_conjugated_bonds(mol) def test_deprecation_warning_max_iter(self): @@ -875,9 +846,7 @@ def test_pdb_names(self): u = mda.Universe(PDB_helix) mol = u.atoms.convert_to.rdkit() names = u.atoms.names - rd_names = np.array( - [a.GetProp("_MDAnalysis_name") for a in mol.GetAtoms()] - ) + rd_names = np.array([a.GetProp("_MDAnalysis_name") for a in mol.GetAtoms()]) assert (names == rd_names).all() @pytest.mark.parametrize( @@ -896,9 +865,7 @@ def test_bond_stereo_not_stereoany(self, smi): assert bond.GetStereo() != Chem.BondStereo.STEREOANY def test_atom_sorter(self): - mol = Chem.MolFromSmiles( - "[H]-[C](-[H])-[C](-[H])-[C]-[C]-[H]", sanitize=False - ) + mol = Chem.MolFromSmiles("[H]-[C](-[H])-[C](-[H])-[C]-[C]-[H]", sanitize=False) # corresponding mol: C=C-C#C # atom indices: 1 3 5 6 mol.UpdatePropertyCache() @@ -914,9 +881,7 @@ def test_atom_sorter(self): [ pytest.param( True, - marks=pytest.mark.xfail( - reason="Invalid charge/valence", strict=True - ), + marks=pytest.mark.xfail(reason="Invalid charge/valence", strict=True), ), False, ], diff --git a/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py b/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py index f82d74a561..a55ad8a449 100644 --- a/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py +++ b/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py @@ -120,9 +120,7 @@ def test_bond_orders(self, top, filename): expected = [bond.GetBondTypeAsDouble() for bond in filename.GetBonds()] assert top.bonds.order == expected - def test_multiple_charge_priority( - self, top_gas_tripos, filename_gasteiger - ): + def test_multiple_charge_priority(self, top_gas_tripos, filename_gasteiger): expected = np.array( [ a.GetDoubleProp("_GasteigerCharge") @@ -141,9 +139,7 @@ def test_multiple_charge_props_warning(self): top = self.parser(mol).parse() # Verify the warning assert len(w) == 1 - assert "_GasteigerCharge and _TriposPartialCharge" in str( - w[-1].message - ) + assert "_GasteigerCharge and _TriposPartialCharge" in str(w[-1].message) def test_gasteiger_charges(self, top_gasteiger, filename_gasteiger): expected = np.array( @@ -157,18 +153,13 @@ def test_gasteiger_charges(self, top_gasteiger, filename_gasteiger): def test_tripos_charges(self, top, filename): expected = np.array( - [ - a.GetDoubleProp("_TriposPartialCharge") - for a in filename.GetAtoms() - ], + [a.GetDoubleProp("_TriposPartialCharge") for a in filename.GetAtoms()], dtype=np.float32, ) assert_equal(expected, top.charges.values) def test_aromaticity(self, top, filename): - expected = np.array( - [atom.GetIsAromatic() for atom in filename.GetAtoms()] - ) + expected = np.array([atom.GetIsAromatic() for atom in filename.GetAtoms()]) assert_equal(expected, top.aromaticities.values) def test_guessed_types(self, filename): @@ -203,9 +194,7 @@ def filename(self): def test_partial_residueinfo_raise_error(self, filename): mol = Chem.RemoveHs(filename) mh = Chem.AddHs(mol) - with pytest.raises( - ValueError, match="ResidueInfo is only partially available" - ): + with pytest.raises(ValueError, match="ResidueInfo is only partially available"): mda.Universe(mh) mh = Chem.AddHs(mol, addResidueInfo=True) mda.Universe(mh) diff --git a/testsuite/MDAnalysisTests/coordinates/base.py b/testsuite/MDAnalysisTests/coordinates/base.py index 1568dfab87..c5704c990f 100644 --- a/testsuite/MDAnalysisTests/coordinates/base.py +++ b/testsuite/MDAnalysisTests/coordinates/base.py @@ -71,9 +71,7 @@ def test_n_atoms(self): ) def test_numres(self): - assert_equal( - self.universe.atoms.n_residues, 214, "wrong number of residues" - ) + assert_equal(self.universe.atoms.n_residues, 214, "wrong number of residues") def test_n_frames(self): assert_equal( @@ -83,16 +81,13 @@ def test_n_frames(self): ) def test_time(self): - assert_equal( - self.universe.trajectory.time, 0.0, "wrong time of the frame" - ) + assert_equal(self.universe.trajectory.time, 0.0, "wrong time of the frame") def test_frame(self): assert_equal( self.universe.trajectory.frame, 0, - "wrong frame number (0-based, should be 0 for single frame " - "readers)", + "wrong frame number (0-based, should be 0 for single frame " "readers)", ) def test_frame_index_0(self): @@ -206,9 +201,7 @@ def __init__(self): [2**8], # frame 4 = 4ps = step 8 ] self.aux_highf_n_steps = 10 - self.aux_highf_all_data = [ - [2**i] for i in range(self.aux_highf_n_steps) - ] + self.aux_highf_all_data = [[2**i] for i in range(self.aux_highf_n_steps)] self.aux_offset_by = 0.25 @@ -239,9 +232,7 @@ def __init__(self): self.jump_to_frame.aux.lowf = self.aux_lowf_data[3] self.jump_to_frame.aux.highf = self.aux_highf_data[3] - self.dimensions = np.array( - [81.1, 82.2, 83.3, 75, 80, 85], dtype=np.float32 - ) + self.dimensions = np.array([81.1, 82.2, 83.3, 75, 80, 85], dtype=np.float32) self.dimensions_second_frame = np.array( [82.1, 83.2, 84.3, 75.1, 80.1, 85.1], dtype=np.float32 ) @@ -285,9 +276,7 @@ def reader(ref): @pytest.fixture() def transformed(ref): transformed = ref.reader(ref.trajectory) - transformed.add_transformations( - translate([1, 1, 1]), translate([0, 0, 0.33]) - ) + transformed.add_transformations(translate([1, 1, 1]), translate([0, 0, 0.33])) return transformed def test_n_atoms(self, ref, reader): @@ -298,9 +287,7 @@ def test_n_frames(self, ref, reader): def test_first_frame(self, ref, reader): reader.rewind() - assert_timestep_almost_equal( - reader.ts, ref.first_frame, decimal=ref.prec - ) + assert_timestep_almost_equal(reader.ts, ref.first_frame, decimal=ref.prec) def test_double_close(self, reader): reader.close() @@ -390,8 +377,7 @@ def test_iter_auxiliary(self, ref, reader): assert_almost_equal( auxstep.data, ref.aux_highf_all_data[i], - err_msg="Auxiliary data does not match for " - "step {}".format(i), + err_msg="Auxiliary data does not match for " "step {}".format(i), ) def test_get_aux_attribute(self, ref, reader): @@ -414,8 +400,7 @@ def test_iter_as_aux_cutoff(self, ref, reader): assert_equal( num_frames, 0, - "iter_as_aux should iterate over 0 frames," - " not {}".format(num_frames), + "iter_as_aux should iterate over 0 frames," " not {}".format(num_frames), ) def test_reload_auxiliaries_from_description(self, ref, reader): @@ -453,9 +438,7 @@ def test_transformations_iter(self, ref, transformed): v2 = np.float32((0, 0, 0.33)) for i, ts in enumerate(transformed): idealcoords = ref.iter_ts(i).positions + v1 + v2 - assert_array_almost_equal( - ts.positions, idealcoords, decimal=ref.prec - ) + assert_array_almost_equal(ts.positions, idealcoords, decimal=ref.prec) def test_transformations_2iter(self, ref, transformed): # Are the transformations applied and @@ -465,9 +448,7 @@ def test_transformations_2iter(self, ref, transformed): idealcoords = [] for i, ts in enumerate(transformed): idealcoords.append(ref.iter_ts(i).positions + v1 + v2) - assert_array_almost_equal( - ts.positions, idealcoords[i], decimal=ref.prec - ) + assert_array_almost_equal(ts.positions, idealcoords[i], decimal=ref.prec) for i, ts in enumerate(transformed): assert_almost_equal(ts.positions, idealcoords[i], decimal=ref.prec) @@ -478,9 +459,7 @@ def test_transformations_slice(self, ref, transformed): v2 = np.float32((0, 0, 0.33)) for i, ts in enumerate(transformed[2:3:1]): idealcoords = ref.iter_ts(ts.frame).positions + v1 + v2 - assert_array_almost_equal( - ts.positions, idealcoords, decimal=ref.prec - ) + assert_array_almost_equal(ts.positions, idealcoords, decimal=ref.prec) def test_transformations_switch_frame(self, ref, transformed): # This test checks if the transformations are applied and if the coordinates @@ -536,9 +515,7 @@ def test_transformations_copy(self, ref, transformed): ) for i, ts in enumerate(new): ideal_coords = ref.iter_ts(i).positions + v1 + v2 - assert_array_almost_equal( - ts.positions, ideal_coords, decimal=ref.prec - ) + assert_array_almost_equal(ts.positions, ideal_coords, decimal=ref.prec) def test_add_another_transformations_raises_ValueError(self, transformed): # After defining the transformations, the workflow cannot be changed @@ -548,9 +525,7 @@ def test_add_another_transformations_raises_ValueError(self, transformed): def test_pickle_reader(self, reader): reader_p = pickle.loads(pickle.dumps(reader)) assert_equal(len(reader), len(reader_p)) - assert_equal( - reader.ts, reader_p.ts, "Timestep is changed after pickling" - ) + assert_equal(reader.ts, reader_p.ts, "Timestep is changed after pickling") reader_p_p = pickle.loads(pickle.dumps(reader_p)) assert_equal(len(reader), len(reader_p_p)) assert_equal( @@ -584,9 +559,7 @@ def test_frame_collect_all_same(self, reader): for array in collected_ts: assert_allclose(array, collected_ts[0]) - @pytest.mark.parametrize( - "order", ("fac", "fca", "afc", "acf", "caf", "cfa") - ) + @pytest.mark.parametrize("order", ("fac", "fca", "afc", "acf", "caf", "cfa")) def test_timeseries_shape(self, reader, order): timeseries = reader.timeseries(order=order) a_index = order.index("a") @@ -628,9 +601,7 @@ def test_timeseries_empty_asel(self, reader): UserWarning, match="Empty string to select atoms, empty group returned.", ): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( - None - ) + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms(None) with pytest.raises(ValueError, match="Timeseries requires at least"): reader.timeseries(asel=atoms) @@ -639,33 +610,23 @@ def test_timeseries_empty_atomgroup(self, reader): UserWarning, match="Empty string to select atoms, empty group returned.", ): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( - None - ) + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms(None) with pytest.raises(ValueError, match="Timeseries requires at least"): reader.timeseries(atomgroup=atoms) def test_timeseries_asel_warns_deprecation(self, reader): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( - "index 1" - ) + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms("index 1") with pytest.warns(DeprecationWarning, match="asel argument to"): timeseries = reader.timeseries(asel=atoms, order="fac") def test_timeseries_atomgroup(self, reader): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( - "index 1" - ) + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms("index 1") timeseries = reader.timeseries(atomgroup=atoms, order="fac") def test_timeseries_atomgroup_asel_mutex(self, reader): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( - "index 1" - ) + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms("index 1") with pytest.raises(ValueError, match="Cannot provide both"): - timeseries = reader.timeseries( - atomgroup=atoms, asel=atoms, order="fac" - ) + timeseries = reader.timeseries(atomgroup=atoms, asel=atoms, order="fac") class MultiframeReaderTest(BaseReaderTest): @@ -768,9 +729,7 @@ def test_pickle_last_ts_reader(self, reader): len(reader_p), "Last timestep is changed after pickling", ) - assert_equal( - reader.ts, reader_p.ts, "Last timestep is changed after pickling" - ) + assert_equal(reader.ts, reader_p.ts, "Last timestep is changed after pickling") class BaseWriterTest(object): @@ -960,9 +919,7 @@ def assert_timestep_almost_equal(A, B, decimal=6, verbose=True): if A.has_forces != B.has_forces: raise AssertionError( "Only one Timestep has forces:" - "A.has_forces = {}, B.has_forces = {}".format( - A.has_forces, B.has_forces - ) + "A.has_forces = {}, B.has_forces = {}".format(A.has_forces, B.has_forces) ) if A.has_forces: assert_array_almost_equal( diff --git a/testsuite/MDAnalysisTests/coordinates/reference.py b/testsuite/MDAnalysisTests/coordinates/reference.py index 8d43a9f925..8452bfab35 100644 --- a/testsuite/MDAnalysisTests/coordinates/reference.py +++ b/testsuite/MDAnalysisTests/coordinates/reference.py @@ -228,9 +228,7 @@ class RefTRZ(object): class RefLAMMPSData(object): filename = LAMMPSdata n_atoms = 18364 - pos_atom1 = np.array( - [11.89985657, 48.4455719, 19.09719849], dtype=np.float32 - ) + pos_atom1 = np.array([11.89985657, 48.4455719, 19.09719849], dtype=np.float32) vel_atom1 = np.array( [-0.005667593, 0.00791380978, -0.00300779533], dtype=np.float32 ) @@ -256,15 +254,11 @@ class RefLAMMPSDataDCD(object): class RefLAMMPSDataMini(object): filename = LAMMPSdata_mini n_atoms = 1 - pos_atom1 = np.array( - [11.89985657, 48.4455719, 19.09719849], dtype=np.float32 - ) + pos_atom1 = np.array([11.89985657, 48.4455719, 19.09719849], dtype=np.float32) vel_atom1 = np.array( [-0.005667593, 0.00791380978, -0.00300779533], dtype=np.float32 ) - dimensions = np.array( - [60.0, 50.0, 30.0, 90.0, 90.0, 90.0], dtype=np.float32 - ) + dimensions = np.array([60.0, 50.0, 30.0, 90.0, 90.0, 90.0], dtype=np.float32) class RefLAMMPSDataAdditionalColumns(object): diff --git a/testsuite/MDAnalysisTests/coordinates/test_chainreader.py b/testsuite/MDAnalysisTests/coordinates/test_chainreader.py index 4614e3e4d1..a54a92681e 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_chainreader.py +++ b/testsuite/MDAnalysisTests/coordinates/test_chainreader.py @@ -82,9 +82,7 @@ def test_next_trajectory(self, universe): assert_equal(universe.trajectory.ts.frame, 1, "loading frame 2") def test_n_atoms(self, universe): - assert_equal( - universe.trajectory.n_atoms, 3341, "wrong number of atoms" - ) + assert_equal(universe.trajectory.n_atoms, 3341, "wrong number of atoms") def test_n_frames(self, universe): assert_equal( @@ -161,9 +159,7 @@ def test_write_dcd(self, universe, tmpdir): ts_orig._pos, ts_new._pos, self.prec, - err_msg="Coordinates disagree at frame {0:d}".format( - ts_orig.frame - ), + err_msg="Coordinates disagree at frame {0:d}".format(ts_orig.frame), ) def test_transform_iteration(self, universe, transformed): @@ -193,26 +189,18 @@ def test_transform_switch(self, universe, transformed): vector = np.float32([10, 10, 10]) # grab a frame: ref = universe.trajectory[2].positions + vector - assert_almost_equal( - transformed.trajectory[2].positions, ref, decimal=6 - ) + assert_almost_equal(transformed.trajectory[2].positions, ref, decimal=6) # now switch to another frame newref = universe.trajectory[10].positions + vector - assert_almost_equal( - transformed.trajectory[10].positions, newref, decimal=6 - ) + assert_almost_equal(transformed.trajectory[10].positions, newref, decimal=6) # what happens when we comeback to the previous frame? - assert_almost_equal( - transformed.trajectory[2].positions, ref, decimal=6 - ) + assert_almost_equal(transformed.trajectory[2].positions, ref, decimal=6) def test_transfrom_rewind(self, universe, transformed): vector = np.float32([10, 10, 10]) ref = universe.trajectory[0].positions + vector transformed.trajectory.rewind() - assert_almost_equal( - transformed.trajectory.ts.positions, ref, decimal=6 - ) + assert_almost_equal(transformed.trajectory.ts.positions, ref, decimal=6) class TestChainReaderCommonDt(object): @@ -242,9 +230,7 @@ class TestChainReaderFormats(object): """Test of ChainReader with explicit formats (Issue 76).""" def test_set_all_format_tuples(self): - universe = mda.Universe( - GRO, [(PDB, "pdb"), (XTC, "xtc"), (TRR, "trr")] - ) + universe = mda.Universe(GRO, [(PDB, "pdb"), (XTC, "xtc"), (TRR, "trr")]) assert universe.trajectory.n_frames == 21 assert_equal(universe.trajectory.filenames, [PDB, XTC, TRR]) @@ -390,9 +376,7 @@ def __init__(self, seq, n_frames, order): ) def test_order(self, seq_info, tmpdir, fmt): folder = str(tmpdir) - utop, fnames = build_trajectories( - folder, sequences=seq_info.seq, fmt=fmt - ) + utop, fnames = build_trajectories(folder, sequences=seq_info.seq, fmt=fmt) u = mda.Universe(utop._topology, fnames, continuous=True, to_guess=()) assert u.trajectory.n_frames == seq_info.n_frames for i, ts in enumerate(u.trajectory): @@ -457,12 +441,8 @@ def test_easy_trigger_warning(self, tmpdir): # TODO: remove when we no longer have a dependency # that still imports six if sys.version_info >= (3, 10): - warnings.filterwarnings( - action="ignore", category=ImportWarning - ) - mda.Universe( - utop._topology, fnames, continuous=True, to_guess=() - ) + warnings.filterwarnings(action="ignore", category=ImportWarning) + mda.Universe(utop._topology, fnames, continuous=True, to_guess=()) def test_single_frames(self, tmpdir): folder = str(tmpdir) diff --git a/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py b/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py index a556414de3..fd489977fe 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py +++ b/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py @@ -54,9 +54,7 @@ def test_version_check(version, monkeypatch): ChemfilesWriter("") -@pytest.mark.skipif( - not check_chemfiles_version(), reason="Wrong version of chemfiles" -) +@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") class TestChemfileXYZ(MultiframeReaderTest): @staticmethod @pytest.fixture @@ -99,9 +97,7 @@ def __init__(self): self.dimensions = None -@pytest.mark.skipif( - not check_chemfiles_version(), reason="Wrong version of chemfiles" -) +@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") class TestChemfilesReader(MultiframeReaderTest): @staticmethod @pytest.fixture() @@ -146,9 +142,7 @@ def test_copy(self, ref): assert_allclose(original.ts.positions, copy.ts.positions) -@pytest.mark.skipif( - not check_chemfiles_version(), reason="Wrong version of chemfiles" -) +@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") class TestChemfilesWriter(BaseWriterTest): @staticmethod @pytest.fixture() @@ -165,9 +159,7 @@ def test_no_extension_raises(self, ref): ref.writer("foo") -@pytest.mark.skipif( - not check_chemfiles_version(), reason="Wrong version of chemfiles" -) +@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") class TestChemfiles(object): def test_read_chemfiles_format(self): u = mda.Universe( @@ -191,9 +183,7 @@ def test_changing_system_size(self, tmpdir): with open(outfile, "w") as fd: fd.write(VARYING_XYZ) - u = mda.Universe( - outfile, format="chemfiles", topology_format="XYZ" - ) + u = mda.Universe(outfile, format="chemfiles", topology_format="XYZ") with pytest.raises(IOError): u.trajectory._read_next_timestep() @@ -204,9 +194,7 @@ def test_wrong_open_mode(self): def check_topology(self, reference, file): u = mda.Universe(reference) - atoms = set( - [(atom.name, atom.type, atom.record_type) for atom in u.atoms] - ) + atoms = set([(atom.name, atom.type, atom.record_type) for atom in u.atoms]) bonds = set([(bond.atoms[0].ix, bond.atoms[1].ix) for bond in u.bonds]) check = mda.Universe(file) diff --git a/testsuite/MDAnalysisTests/coordinates/test_copying.py b/testsuite/MDAnalysisTests/coordinates/test_copying.py index 6a6cd86590..c8d32ac721 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_copying.py +++ b/testsuite/MDAnalysisTests/coordinates/test_copying.py @@ -288,9 +288,7 @@ def test_timestep_copied(ref_reader): assert new.ts.positions.dtype == np.float32 -@pytest.mark.skipif( - shares_memory == False, reason="old numpy lacked shares_memory" -) +@pytest.mark.skipif(shares_memory == False, reason="old numpy lacked shares_memory") def test_positions_share_memory(original_and_copy): # check that the memory in Timestep objects is unique original, copy = original_and_copy diff --git a/testsuite/MDAnalysisTests/coordinates/test_crd.py b/testsuite/MDAnalysisTests/coordinates/test_crd.py index be68d82eae..edbd4886b9 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_crd.py +++ b/testsuite/MDAnalysisTests/coordinates/test_crd.py @@ -41,9 +41,7 @@ def u(self): def outfile(self, tmpdir): return os.path.join(str(tmpdir), "test.crd") - @pytest.mark.parametrize( - "testfile", ["test.crd", "test.crd.bz2", "test.crd.gz"] - ) + @pytest.mark.parametrize("testfile", ["test.crd", "test.crd.bz2", "test.crd.gz"]) def test_write_atoms(self, u, testfile, tmpdir): # Test that written file when read gives same coordinates with tmpdir.as_cwd(): @@ -137,6 +135,4 @@ def test_write(self, missing_attr, tmpdir): for attr in attrs: assert_equal(getattr(u.atoms, attr), getattr(u2.atoms, attr)) # Check missing attr is as expected - assert_equal( - getattr(u2.atoms, missing_attr), self.req_attrs[missing_attr] - ) + assert_equal(getattr(u2.atoms, missing_attr), self.req_attrs[missing_attr]) diff --git a/testsuite/MDAnalysisTests/coordinates/test_dcd.py b/testsuite/MDAnalysisTests/coordinates/test_dcd.py index 0eea9cb4cd..598eb89e40 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_dcd.py +++ b/testsuite/MDAnalysisTests/coordinates/test_dcd.py @@ -210,9 +210,7 @@ def test_array_like(universe_dcd, array_like): assert_array_equal(frames, ar) -@pytest.mark.parametrize( - "indices", ([0, 4, 2, 3, 0, 1], [0, 0, 1, 1, 2, 1, 1]) -) +@pytest.mark.parametrize("indices", ([0, 4, 2, 3, 0, 1], [0, 0, 1, 1, 2, 1, 1])) def test_list_indices(universe_dcd, indices): frames = [ts.frame for ts in universe_dcd.trajectory[indices]] assert_array_equal(frames, indices) @@ -268,9 +266,7 @@ def test_timeseries_order(order, shape, universe_dcd): assert x.shape == shape -@pytest.mark.parametrize( - "indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]] -) +@pytest.mark.parametrize("indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]]) def test_timeseries_atomindices(indices, universe_dcd): allframes = universe_dcd.trajectory.timeseries(order="afc") asel = universe_dcd.atoms[indices] @@ -356,9 +352,7 @@ def test_other_writer(universe_dcd, tmpdir, ext, decimal): decimal, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame {} (orig) vs {} (written)".format( - orig_ts.frame, written_ts.frame - ), + "frame {} (orig) vs {} (written)".format(orig_ts.frame, written_ts.frame), ) @@ -505,8 +499,7 @@ def test_ts_time(universe): u = universe header = u.trajectory._file.header ref_times = [ - (ts.frame + header["istart"] / header["nsavc"]) * ts.dt - for ts in u.trajectory + (ts.frame + header["istart"] / header["nsavc"]) * ts.dt for ts in u.trajectory ] times = [ts.time for ts in u.trajectory] assert_almost_equal(times, ref_times, decimal=5) diff --git a/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py b/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py index 63d0a09464..786a362e2f 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py +++ b/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py @@ -58,9 +58,7 @@ def test_read_unitcell(self, ts): [0.0000000000, 0.0000000000, 18.6960000000], ] ) - assert_allclose( - ts.dimensions, mda.coordinates.core.triclinic_box(*ref) - ) + assert_allclose(ts.dimensions, mda.coordinates.core.triclinic_box(*ref)) def test_positions(self, ts): ref = np.array([-7.608595309, -7.897790000, -7.892053559]) @@ -220,9 +218,7 @@ def test_unitcell(self, u): ] ) for ts, r in zip(u.trajectory, [ref1, ref2, ref3]): - assert_allclose( - ts.dimensions, mda.coordinates.core.triclinic_box(*r) - ) + assert_allclose(ts.dimensions, mda.coordinates.core.triclinic_box(*r)) class TestDLPolyHistory(_DLHistory): diff --git a/testsuite/MDAnalysisTests/coordinates/test_dms.py b/testsuite/MDAnalysisTests/coordinates/test_dms.py index e4d9ac1ee6..820703761f 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_dms.py +++ b/testsuite/MDAnalysisTests/coordinates/test_dms.py @@ -67,9 +67,7 @@ def test_coords_atom_0(self, universe): assert_equal(universe.atoms[0].position, coords_0) def test_n_frames(self, universe): - assert_equal( - universe.trajectory.n_frames, 1, "wrong number of frames in pdb" - ) + assert_equal(universe.trajectory.n_frames, 1, "wrong number of frames in pdb") def test_time(self, universe): assert_equal(universe.trajectory.time, 0.0, "wrong time of the frame") @@ -78,8 +76,7 @@ def test_frame(self, universe): assert_equal( universe.trajectory.frame, 0, - "wrong frame number " - "(0-based, should be 0 for single frame readers)", + "wrong frame number " "(0-based, should be 0 for single frame readers)", ) def test_frame_index_0(self, universe): diff --git a/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py b/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py index f1ec55b191..187c9c5cea 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py +++ b/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py @@ -69,9 +69,7 @@ class RefFHIAIMS(object): filename, trajectory, topology = [FHIAIMS] * 3 reader, writer = FHIAIMSReader, FHIAIMSWriter pos_atom1 = np.asarray([6.861735, 2.103823, 37.753513], dtype=np.float32) - dimensions = np.asarray( - [18.6, 18.6, 55.8, 90.0, 90.0, 90.0], dtype=np.float32 - ) + dimensions = np.asarray([18.6, 18.6, 55.8, 90.0, 90.0, 90.0], dtype=np.float32) n_atoms = 6 n_frames = 1 time = 0.0 @@ -87,7 +85,9 @@ class TestFHIAIMSReader(object): @pytest.fixture(scope="class") def bad_input_missing_periodicity(self): - buffer = "lattice_vector 1.0 0.0 0.0\nlattice_vector 0.0 1.0 0.0\natom 0.1 0.1 0.1 H" + buffer = ( + "lattice_vector 1.0 0.0 0.0\nlattice_vector 0.0 1.0 0.0\natom 0.1 0.1 0.1 H" + ) return StringIO(buffer) @pytest.fixture(scope="class") @@ -162,13 +162,9 @@ def test_n_frames(self, ref, universe): ) def test_time(self, ref, universe): - assert_equal( - ref.time, universe.trajectory.time, "wrong time of the frame" - ) + assert_equal(ref.time, universe.trajectory.time, "wrong time of the frame") - def test_bad_input_missing_periodicity( - self, bad_input_missing_periodicity - ): + def test_bad_input_missing_periodicity(self, bad_input_missing_periodicity): with pytest.raises(ValueError, match="Found partial periodicity"): u = mda.Universe(bad_input_missing_periodicity, format="FHIAIMS") @@ -179,25 +175,17 @@ def test_bad_input_relative_positions_no_box( ValueError, match="Found relative coordinates in FHI-AIMS file without lattice info", ): - u = mda.Universe( - bad_input_relative_positions_no_box, format="FHIAIMS" - ) + u = mda.Universe(bad_input_relative_positions_no_box, format="FHIAIMS") def test_bad_input_missing_velocity(self, bad_input_missing_velocity): - with pytest.raises( - ValueError, match="Found incorrect number of velocity tags" - ): + with pytest.raises(ValueError, match="Found incorrect number of velocity tags"): u = mda.Universe(bad_input_missing_velocity, format="FHIAIMS") - def test_bad_input_velocity_wrong_position( - self, bad_input_velocity_wrong_position - ): + def test_bad_input_velocity_wrong_position(self, bad_input_velocity_wrong_position): with pytest.raises( ValueError, match="Non-conforming line .velocity must follow" ): - u = mda.Universe( - bad_input_velocity_wrong_position, format="FHIAIMS" - ) + u = mda.Universe(bad_input_velocity_wrong_position, format="FHIAIMS") def test_bad_input_wrong_input_line(self, bad_input_wrong_input_line): with pytest.raises(ValueError, match="Non-conforming line"): @@ -212,9 +200,7 @@ def test_good_input_with_velocity(self, good_input_with_velocity): "FHIAIMSReader failed to read velocities properly", ) - def test_mixed_units( - self, good_input_natural_units, good_input_mixed_units - ): + def test_mixed_units(self, good_input_natural_units, good_input_mixed_units): u_natural = mda.Universe(good_input_natural_units, format="FHIAIMS") u_mixed = mda.Universe(good_input_mixed_units, format="FHIAIMS") print(u_natural.atoms.positions) @@ -234,9 +220,7 @@ class TestFHIAIMSWriter(BaseWriterTest): @pytest.fixture def outfile(self, tmpdir): return str( - tmpdir.mkdir("FHIAIMSWriter").join( - "primitive-fhiaims-writer" + self.ext - ) + tmpdir.mkdir("FHIAIMSWriter").join("primitive-fhiaims-writer" + self.ext) ) def test_writer(self, universe, outfile): @@ -279,9 +263,7 @@ def test_writer_with_n_atoms_none(self, good_input_natural_units, outfile): assert line.startswith( "atom" ), "Line written incorrectly with FHIAIMSWriter" - assert line.endswith( - "H" - ), "Line written incorrectly with FHIAIMSWriter" + assert line.endswith("H"), "Line written incorrectly with FHIAIMSWriter" line = np.asarray(line.split()[1:-1], dtype=np.float32) assert_almost_equal( line, diff --git a/testsuite/MDAnalysisTests/coordinates/test_gms.py b/testsuite/MDAnalysisTests/coordinates/test_gms.py index 355e0658ba..4b7ee7c7e3 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_gms.py +++ b/testsuite/MDAnalysisTests/coordinates/test_gms.py @@ -78,9 +78,7 @@ def test_next(self, u): assert_equal(u.trajectory.ts.frame, 1, "loading frame 1") def test_dt(self, u): - assert_almost_equal( - u.trajectory.dt, 1.0, 4, err_msg="wrong timestep dt" - ) + assert_almost_equal(u.trajectory.dt, 1.0, 4, err_msg="wrong timestep dt") def test_step5distances(self, u): assert_almost_equal( diff --git a/testsuite/MDAnalysisTests/coordinates/test_gro.py b/testsuite/MDAnalysisTests/coordinates/test_gro.py index c307bdc8ca..5f3d7f9123 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_gro.py +++ b/testsuite/MDAnalysisTests/coordinates/test_gro.py @@ -61,9 +61,7 @@ def universe(self): def test_load_gro(self, universe): U = universe - assert_equal( - len(U.atoms), self.ref_n_atoms, "load Universe from small GRO" - ) + assert_equal(len(U.atoms), self.ref_n_atoms, "load Universe from small GRO") assert_equal( U.atoms.select_atoms("resid 150 and name HA2").atoms[0], U.atoms[self.ref_E151HA2_index], @@ -330,9 +328,7 @@ def reader(ref): @pytest.fixture(scope="class") def transformed(ref): transformed = ref.reader(ref.trajectory, convert_units=False) - transformed.add_transformations( - translate([1, 1, 1]), translate([0, 0, 0.33]) - ) + transformed.add_transformations(translate([1, 1, 1]), translate([0, 0, 0.33])) return transformed @@ -424,9 +420,7 @@ def test_writer_large(self, ref, tmpdir): u.atoms.write(outfile) with open(outfile, "rt") as mda_output: - with mda.lib.util.anyopen( - ref.topology, "rt" - ) as expected_output: + with mda.lib.util.anyopen(ref.topology, "rt") as expected_output: produced_lines = mda_output.readlines()[1:] expected_lines = expected_output.readlines()[1:] assert_equal( @@ -531,9 +525,7 @@ def test_multiframe_gro(): # for now, single frame read assert len(u.trajectory) == 1 - assert_equal( - u.dimensions, np.array([100, 100, 100, 90, 90, 90], dtype=np.float32) - ) + assert_equal(u.dimensions, np.array([100, 100, 100, 90, 90, 90], dtype=np.float32)) def test_huge_box_gro(): diff --git a/testsuite/MDAnalysisTests/coordinates/test_h5md.py b/testsuite/MDAnalysisTests/coordinates/test_h5md.py index 1524ca7f62..3587de1ef1 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_h5md.py +++ b/testsuite/MDAnalysisTests/coordinates/test_h5md.py @@ -311,24 +311,19 @@ def test_jump_last_frame(self, universe): @pytest.mark.parametrize("start, stop, step", ((0, 2, 1), (1, 2, 1))) def test_slice(self, universe, start, stop, step): frames = [ - universe.trajectory.ts.frame - for ts in universe.trajectory[start:stop:step] + universe.trajectory.ts.frame for ts in universe.trajectory[start:stop:step] ] assert_equal(frames, np.arange(start, stop, step)) @pytest.mark.parametrize("array_like", [list, np.array]) def test_array_like(self, universe, array_like): array = array_like([0, 2]) - frames = [ - universe.trajectory.ts.frame for ts in universe.trajectory[array] - ] + frames = [universe.trajectory.ts.frame for ts in universe.trajectory[array]] assert_equal(frames, array) def test_list_indices(self, universe): indices = [0, 1, 2, 1, 2, 2, 0] - frames = [ - universe.trajectory.ts.frame for ts in universe.trajectory[indices] - ] + frames = [universe.trajectory.ts.frame for ts in universe.trajectory[indices]] assert_equal(frames, indices) @pytest.mark.parametrize( @@ -358,12 +353,8 @@ def test_unknown_unit(self, h5md_file, outfile, dset): with h5py.File(outfile, "w") as g: f.copy(source="particles", dest=g) f.copy(source="h5md", dest=g) - g["particles" "/trajectory" f"/{dset}"].attrs[ - "unit" - ] = "random string" - with pytest.raises( - RuntimeError, match=" is not recognized by H5MDReader." - ): + g["particles" "/trajectory" f"/{dset}"].attrs["unit"] = "random string" + with pytest.raises(RuntimeError, match=" is not recognized by H5MDReader."): u = mda.Universe(TPR_xvf, outfile) def test_length_unit_from_box(self, h5md_file, universe, outfile): @@ -374,14 +365,10 @@ def test_length_unit_from_box(self, h5md_file, universe, outfile): del g["particles/trajectory/position"] ref_u = universe uw = mda.Universe(TPR_xvf, outfile) - assert_equal( - ref_u.trajectory.units["length"], uw.trajectory.units["length"] - ) + assert_equal(ref_u.trajectory.units["length"], uw.trajectory.units["length"]) for ref_ts, new_ts in zip(ref_u.trajectory, uw.trajectory): assert_equal(ref_ts.dimensions, new_ts.dimensions) - assert_equal( - ref_ts.triclinic_dimensions, new_ts.triclinic_dimensions - ) + assert_equal(ref_ts.triclinic_dimensions, new_ts.triclinic_dimensions) @pytest.mark.parametrize("group", ("position", "velocity", "force")) def test_changing_n_atoms(self, h5md_file, outfile, group): @@ -406,9 +393,7 @@ def test_2D_box(self, h5md_file, outfile): g["particles/trajectory" "/box/edges"].create_dataset( "value", data=new_box ) - with pytest.raises( - ValueError, match="MDAnalysis only supports 3-dimensional" - ): + with pytest.raises(ValueError, match="MDAnalysis only supports 3-dimensional"): u = mda.Universe(TPR_xvf, outfile) def test_box_vector(self, h5md_file, outfile): @@ -444,9 +429,7 @@ def test_no_groups(self, h5md_file, outfile): del g["particles/trajectory/position"] del g["particles/trajectory/velocity"] del g["particles/trajectory/force"] - with pytest.raises( - NoDataError, match="Provide at least a position, velocity" - ): + with pytest.raises(NoDataError, match="Provide at least a position, velocity"): u = mda.Universe(TPR_xvf, outfile) def test_no_convert_units(self, h5md_file, outfile): @@ -472,9 +455,7 @@ def test_no_units_but_convert_units_true_error(self, h5md_file, outfile): del g["particles/trajectory"][name]["value"].attrs["unit"] del g["particles/trajectory/position/time"].attrs["unit"] del g["particles/trajectory/box/edges/value"].attrs["unit"] - with pytest.raises( - ValueError, match="H5MD file must have readable units if" - ): + with pytest.raises(ValueError, match="H5MD file must have readable units if"): u = mda.Universe(TPR_xvf, outfile, convert_units=True) @pytest.mark.xfail(reason="Issue #2884") @@ -583,9 +564,7 @@ def outtop(self, tmpdir): (0.5, IOError, "H5MDWriter: Timestep does not have"), ), ) - def test_n_atoms_errors( - self, universe, Writer, outfile, scalar, error, match - ): + def test_n_atoms_errors(self, universe, Writer, outfile, scalar, error, match): n_atoms = universe.atoms.n_atoms * scalar with pytest.raises(error, match=match): with Writer(outfile, n_atoms) as W: @@ -665,9 +644,7 @@ def test_has_property(self, universe, Writer, outfile): (False, False, False), ), ) - def test_write_trajectory( - self, universe, Writer, outfile, pos, vel, force - ): + def test_write_trajectory(self, universe, Writer, outfile, pos, vel, force): try: with Writer( outfile, @@ -685,31 +662,21 @@ def test_write_trajectory( # check the trajectory contents match reference universes for ts, ref_ts in zip(uw.trajectory, universe.trajectory): - assert_almost_equal( - ts.dimensions, ref_ts.dimensions, self.prec - ) + assert_almost_equal(ts.dimensions, ref_ts.dimensions, self.prec) if pos: assert_almost_equal(ts._pos, ref_ts._pos, self.prec) else: - with pytest.raises( - NoDataError, match="This Timestep has no" - ): + with pytest.raises(NoDataError, match="This Timestep has no"): getattr(ts, "positions") if vel: - assert_almost_equal( - ts._velocities, ref_ts._velocities, self.prec - ) + assert_almost_equal(ts._velocities, ref_ts._velocities, self.prec) else: - with pytest.raises( - NoDataError, match="This Timestep has no" - ): + with pytest.raises(NoDataError, match="This Timestep has no"): getattr(ts, "velocities") if force: assert_almost_equal(ts._forces, ref_ts._forces, self.prec) else: - with pytest.raises( - NoDataError, match="This Timestep has no" - ): + with pytest.raises(NoDataError, match="This Timestep has no"): getattr(ts, "forces") # when (False, False, False) @@ -743,14 +710,10 @@ def test_write_AtomGroup_with(self, universe, outfile, outtop, Writer): for orig_ts, written_ts in zip(universe.trajectory, uw.trajectory): assert_almost_equal(ca.positions, caw.positions, self.prec) assert_almost_equal(orig_ts.time, written_ts.time, self.prec) - assert_almost_equal( - written_ts.dimensions, orig_ts.dimensions, self.prec - ) + assert_almost_equal(written_ts.dimensions, orig_ts.dimensions, self.prec) @pytest.mark.parametrize("frames, n_frames", ((None, 1), ("all", 3))) - def test_ag_write( - self, universe, outfile, outtop, Writer, frames, n_frames - ): + def test_ag_write(self, universe, outfile, outtop, Writer, frames, n_frames): """test to write with ag.write()""" ca = universe.select_atoms("protein and name CA") ca.write(outtop) @@ -764,9 +727,7 @@ def test_ag_write( for orig_ts, written_ts in zip(universe.trajectory, uw.trajectory): assert_almost_equal(ca.positions, caw.positions, self.prec) assert_almost_equal(orig_ts.time, written_ts.time, self.prec) - assert_almost_equal( - written_ts.dimensions, orig_ts.dimensions, self.prec - ) + assert_almost_equal(written_ts.dimensions, orig_ts.dimensions, self.prec) @pytest.mark.parametrize( "timeunit, lengthunit, velocityunit, forceunit", @@ -853,12 +814,8 @@ def test_no_units_w_convert_true(self, universe_no_units, outfile, Writer): for ts in universe_no_units.trajectory: W.write(universe_no_units) - def test_no_units_w_convert_false( - self, universe_no_units, outfile, Writer - ): - with Writer( - outfile, universe_no_units.atoms.n_atoms, convert_units=False - ) as W: + def test_no_units_w_convert_false(self, universe_no_units, outfile, Writer): + with Writer(outfile, universe_no_units.atoms.n_atoms, convert_units=False) as W: for ts in universe_no_units.trajectory: W.write(universe_no_units) @@ -868,9 +825,7 @@ def test_no_units_w_convert_false( @pytest.mark.parametrize("convert_units", (True, False)) def test_convert_units(self, universe, outfile, Writer, convert_units): - with Writer( - outfile, universe.atoms.n_atoms, convert_units=convert_units - ) as W: + with Writer(outfile, universe.atoms.n_atoms, convert_units=convert_units) as W: for ts in universe.trajectory: W.write(universe) @@ -880,9 +835,7 @@ def test_convert_units(self, universe, outfile, Writer, convert_units): for u1, u2 in zip(ref_units, uw_units): assert_equal(u1, u2) - @pytest.mark.parametrize( - "chunks", ((3, 1000, 1), (1, 1000, 3), (100, 100, 3)) - ) + @pytest.mark.parametrize("chunks", ((3, 1000, 1), (1, 1000, 3), (100, 100, 3))) def test_write_chunks(self, universe, outfile, Writer, chunks): with Writer(outfile, universe.atoms.n_atoms, chunks=chunks) as W: for ts in universe.trajectory: @@ -924,9 +877,7 @@ def test_write_chunks_with_nframes(self, universe, outfile, Writer): def test_write_contiguous1(self, universe, Writer, outfile): n_atoms = universe.atoms.n_atoms n_frames = len(universe.trajectory) - with Writer( - outfile, n_atoms=n_atoms, n_frames=n_frames, chunks=False - ) as W: + with Writer(outfile, n_atoms=n_atoms, n_frames=n_frames, chunks=False) as W: for ts in universe.trajectory: W.write(universe) @@ -951,12 +902,8 @@ def test_write_contiguous2(self, universe, Writer, outfile): ): assert_equal(dset.chunks, None) - @pytest.mark.parametrize( - "filter, opts", (("gzip", 1), ("gzip", 9), ("lzf", None)) - ) - def test_write_with_compression( - self, universe, outfile, Writer, filter, opts - ): + @pytest.mark.parametrize("filter, opts", (("gzip", 1), ("gzip", 9), ("lzf", None))) + def test_write_with_compression(self, universe, outfile, Writer, filter, opts): with Writer( outfile, universe.atoms.n_atoms, @@ -971,9 +918,7 @@ def test_write_with_compression( assert_equal(dset.compression, filter) assert_equal(dset.compression_opts, opts) - @pytest.mark.xfail( - os.name == "nt", reason="occasional PermissionError on windows" - ) + @pytest.mark.xfail(os.name == "nt", reason="occasional PermissionError on windows") @pytest.mark.parametrize("driver", ("core", "stdio")) def test_write_with_drivers(self, universe, outfile, Writer, driver): with Writer(outfile, universe.atoms.n_atoms, driver=driver) as W: @@ -1010,9 +955,7 @@ def test_timestep_not_modified_by_writer(self, universe, Writer, outfile): x, err_msg="Positions in Timestep were modified by writer.", ) - assert_equal( - ts.time, time, err_msg="Time in Timestep was modified by writer." - ) + assert_equal(ts.time, time, err_msg="Time in Timestep was modified by writer.") class TestH5PYNotInstalled(object): @@ -1038,9 +981,7 @@ def test_reader_no_h5py(self): def test_writer_no_h5py(self, Writer, outfile): u = mda.Universe(TPR_xvf, TRR_xvf) - with pytest.raises( - RuntimeError, match="H5MDWriter: Please install h5py" - ): + with pytest.raises(RuntimeError, match="H5MDWriter: Please install h5py"): with Writer(outfile, u.atoms.n_atoms) as W: for ts in u.trajectory: W.write(universe) diff --git a/testsuite/MDAnalysisTests/coordinates/test_lammps.py b/testsuite/MDAnalysisTests/coordinates/test_lammps.py index 3b203f5bae..c20f39ecf9 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_lammps.py +++ b/testsuite/MDAnalysisTests/coordinates/test_lammps.py @@ -222,18 +222,14 @@ def test_Writer_atoms_types(self, LAMMPSDATAWriter): err_msg="attributes different after writing", ) - @pytest.mark.parametrize( - "attr", ["bonds", "angles", "dihedrals", "impropers"] - ) + @pytest.mark.parametrize("attr", ["bonds", "angles", "dihedrals", "impropers"]) def test_Writer_atoms(self, attr, LAMMPSDATAWriter): u_ref, u_new = LAMMPSDATAWriter ref = getattr(u_ref.atoms, attr) new = getattr(u_new.atoms, attr) assert ref == new, "attributes different after writing" - @pytest.mark.parametrize( - "attr", ["masses", "charges", "velocities", "positions"] - ) + @pytest.mark.parametrize("attr", ["masses", "charges", "velocities", "positions"]) def test_Writer_numerical_attrs(self, attr, LAMMPSDATAWriter): u_ref, u_new = LAMMPSDATAWriter try: @@ -260,9 +256,7 @@ def test_molecule_tag(self, LAMMPSDATAWriter_molecule_tag): ) -@pytest.mark.parametrize( - "filename", ["out.data", "out.data.bz2", "out.data.gz"] -) +@pytest.mark.parametrize("filename", ["out.data", "out.data.bz2", "out.data.gz"]) def test_datawriter_universe(filename, tmpdir): """ Test roundtrip on datawriter, and also checks compressed files @@ -300,9 +294,7 @@ def LAMMPSDATA_partial(tmpdir): return u, u_new - @pytest.mark.parametrize( - "attr", ["masses", "charges", "velocities", "positions"] - ) + @pytest.mark.parametrize("attr", ["masses", "charges", "velocities", "positions"]) def test_Writer_atoms(self, attr, LAMMPSDATA_partial): u_ref, u_new = LAMMPSDATA_partial if hasattr(u_ref.atoms, attr): @@ -350,9 +342,7 @@ def test_n_frames(self, u): assert_equal(u.trajectory.n_frames, self.n_frames) def test_dimensions(self, u): - mean_dimensions = np.mean( - [ts.dimensions.copy() for ts in u.trajectory], axis=0 - ) + mean_dimensions = np.mean([ts.dimensions.copy() for ts in u.trajectory], axis=0) assert_allclose(mean_dimensions, self.mean_dimensions) def test_dt(self, u): @@ -367,15 +357,11 @@ def test_Timestep_time(self, u): assert_allclose( u.trajectory[iframe].time, iframe * self.dt, - err_msg="Time for frame {0} (dt={1}) is wrong.".format( - iframe, self.dt - ), + err_msg="Time for frame {0} (dt={1}) is wrong.".format(iframe, self.dt), ) def test_LAMMPSDCDReader_set_dt(self, u, dt=1500.0): - u = mda.Universe( - self.topology, self.trajectory, format=self.format, dt=dt - ) + u = mda.Universe(self.topology, self.trajectory, format=self.format, dt=dt) iframe = self.get_frame_from_end(1, u) assert_allclose( u.trajectory[iframe].time, @@ -419,18 +405,14 @@ def u(self): def test_Writer_is_LAMMPS(self, u, tmpdir): ext = os.path.splitext(self.trajectory)[1] outfile = str(tmpdir.join("lammps-writer-test" + ext)) - with mda.Writer( - outfile, n_atoms=u.atoms.n_atoms, format=self.format - ) as W: + with mda.Writer(outfile, n_atoms=u.atoms.n_atoms, format=self.format) as W: assert W.flavor, self.flavor def test_Writer(self, u, tmpdir, n_frames=3): ext = os.path.splitext(self.trajectory)[1] outfile = str(tmpdir.join("lammps-writer-test" + ext)) - with mda.Writer( - outfile, n_atoms=u.atoms.n_atoms, format=self.format - ) as w: + with mda.Writer(outfile, n_atoms=u.atoms.n_atoms, format=self.format) as w: for ts in u.trajectory[:n_frames]: w.write(u) @@ -506,9 +488,7 @@ def test_open(self, tmpdir): def test_wrong_time_unit(self, tmpdir): outfile = str(tmpdir.join("lammps-writer-test.dcd")) with pytest.raises(TypeError): - with mda.coordinates.LAMMPS.DCDWriter( - outfile, n_atoms=10, timeunit="nm" - ): + with mda.coordinates.LAMMPS.DCDWriter(outfile, n_atoms=10, timeunit="nm"): pass def test_wrong_unit(self, tmpdir): @@ -583,9 +563,7 @@ def u(self, tmpdir, request): with gzip.GzipFile(f, "wb") as fout: fout.write(data) - yield mda.Universe( - f, format="LAMMPSDUMP", lammps_coordinate_convention="auto" - ) + yield mda.Universe(f, format="LAMMPSDUMP", lammps_coordinate_convention="auto") @pytest.fixture() def u_additional_columns_true(self): @@ -703,15 +681,9 @@ def test_seeking(self, u, reference_positions): u.trajectory[1] assert_allclose(u.dimensions, reference_positions["box"][1], atol=1e-5) - pos = ( - reference_positions["atom1_pos"][1] - - reference_positions["mins"][1] - ) + pos = reference_positions["atom1_pos"][1] - reference_positions["mins"][1] assert_allclose(u.atoms[0].position, pos, atol=1e-5) - pos = ( - reference_positions["atom13_pos"][1] - - reference_positions["mins"][1] - ) + pos = reference_positions["atom13_pos"][1] - reference_positions["mins"][1] assert_allclose(u.atoms[12].position, pos, atol=1e-5) def test_boxsize(self, u, reference_positions): @@ -742,9 +714,7 @@ def test_additional_columns(self, system, fields, request): u = request.getfixturevalue(system) for field in fields: data = u.trajectory[0].data[field] - assert_allclose( - data, getattr(RefLAMMPSDataAdditionalColumns, field) - ) + assert_allclose(data, getattr(RefLAMMPSDataAdditionalColumns, field)) @pytest.mark.parametrize( "system", @@ -753,9 +723,7 @@ def test_additional_columns(self, system, fields, request): ], ) def test_wrong_format_additional_colums(self, system, request): - with pytest.raises( - ValueError, match="Please provide an iterable containing" - ): + with pytest.raises(ValueError, match="Please provide an iterable containing"): request.getfixturevalue(system) @pytest.mark.parametrize( @@ -769,9 +737,7 @@ def test_warning(self, system, request): request.getfixturevalue(system) -@pytest.mark.parametrize( - "convention", ["unscaled", "unwrapped", "scaled_unwrapped"] -) +@pytest.mark.parametrize("convention", ["unscaled", "unwrapped", "scaled_unwrapped"]) def test_open_absent_convention_fails(convention): with pytest.raises(ValueError, match="No coordinates following"): mda.Universe( @@ -783,9 +749,7 @@ def test_open_absent_convention_fails(convention): def test_open_incorrect_convention_fails(): with pytest.raises(ValueError, match="is not a valid option"): - mda.Universe( - LAMMPSDUMP, format="LAMMPSDUMP", lammps_coordinate_convention="42" - ) + mda.Universe(LAMMPSDUMP, format="LAMMPSDUMP", lammps_coordinate_convention="42") @pytest.mark.parametrize( @@ -887,9 +851,7 @@ def reference_unwrapped_positions(self): ] ) - def test_unwrapped_scaled_reference( - self, universes, reference_unwrapped_positions - ): + def test_unwrapped_scaled_reference(self, universes, reference_unwrapped_positions): atom_340 = universes["unwrapped"].atoms[339] for i, ts_u in enumerate(universes["unwrapped"].trajectory[0:3]): assert_allclose( @@ -898,14 +860,10 @@ def test_unwrapped_scaled_reference( atol=1e-5, ) - def test_unwrapped_scaled_reference( - self, universes, reference_unwrapped_positions - ): + def test_unwrapped_scaled_reference(self, universes, reference_unwrapped_positions): # NOTE use of unscaled positions here due to S->R transform atom_340 = universes["scaled_unwrapped"].atoms[339] - for i, ts_u in enumerate( - universes["scaled_unwrapped"].trajectory[0:3] - ): + for i, ts_u in enumerate(universes["scaled_unwrapped"].trajectory[0:3]): assert_allclose( atom_340.position, reference_unwrapped_positions[i, :], @@ -985,8 +943,6 @@ def test_box(self, u_dump, u_data, reference_box): assert_allclose(ts.dimensions, reference_box, rtol=1e-5, atol=0) for ts in u_dump.trajectory: - assert_allclose( - ts.dimensions, u_data.dimensions, rtol=1e-5, atol=0 - ) + assert_allclose(ts.dimensions, u_data.dimensions, rtol=1e-5, atol=0) assert_allclose(u_data.dimensions, reference_box, rtol=1e-5, atol=0) diff --git a/testsuite/MDAnalysisTests/coordinates/test_memory.py b/testsuite/MDAnalysisTests/coordinates/test_memory.py index 5d020d43d2..27c7e09216 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_memory.py +++ b/testsuite/MDAnalysisTests/coordinates/test_memory.py @@ -73,9 +73,7 @@ def __init__(self): self.jump_to_frame.time = self.jump_to_frame.frame * self.dt def reader(self, trajectory): - return mda.Universe( - self.topology, trajectory, in_memory=True - ).trajectory + return mda.Universe(self.topology, trajectory, in_memory=True).trajectory def iter_ts(self, i): ts = self.universe.trajectory[i] @@ -100,9 +98,7 @@ def test_filename_array(self): # filename attribute of MemoryReader should be None when generated from an array universe = mda.Universe(PSF, DCD) coordinates = universe.trajectory.timeseries(universe.atoms) - universe2 = mda.Universe( - PSF, coordinates, format=MemoryReader, order="afc" - ) + universe2 = mda.Universe(PSF, coordinates, format=MemoryReader, order="afc") assert universe2.trajectory.filename is None def test_default_memory_layout(self): @@ -141,9 +137,7 @@ def test_extract_array_caf(self, reader): assert_equal(reader.timeseries(order="caf").shape, (3, 3341, 98)) def test_timeseries_skip1(self, ref, reader): - assert_equal( - reader.timeseries(ref.universe.atoms).shape, (3341, 98, 3) - ) + assert_equal(reader.timeseries(ref.universe.atoms).shape, (3341, 98, 3)) def test_timeseries_skip10(self, reader): # Check that timeseries skip works similar to numpy slicing @@ -174,9 +168,7 @@ def test_timeseries_view_from_select_all(self, ref, reader): # timeseries() is expected to provide a view of the underlying array # also in the special case when using "all" in selections. selection = ref.universe.select_atoms("all") - assert_equal( - reader.timeseries(asel=selection).base is reader.get_array(), True - ) + assert_equal(reader.timeseries(asel=selection).base is reader.get_array(), True) def test_timeseries_noview(self, ref, reader): # timeseries() is expected NOT to provide a view of the underlying array @@ -200,12 +192,8 @@ def test_float32(self, ref): coordinates = np.random.uniform( size=(100, ref.universe.atoms.n_atoms, 3) ).cumsum(0) - universe = mda.Universe( - ref.universe.filename, coordinates, format=MemoryReader - ) - assert_equal( - universe.trajectory.get_array().dtype, np.dtype("float32") - ) + universe = mda.Universe(ref.universe.filename, coordinates, format=MemoryReader) + assert_equal(universe.trajectory.get_array().dtype, np.dtype("float32")) def test_position_assignation(self, reader): # When coordinates are assigned to a timestep, is the change persistent? diff --git a/testsuite/MDAnalysisTests/coordinates/test_mol2.py b/testsuite/MDAnalysisTests/coordinates/test_mol2.py index 494b2ace2a..cc6761fd48 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_mol2.py +++ b/testsuite/MDAnalysisTests/coordinates/test_mol2.py @@ -55,9 +55,7 @@ def test_read(self): assert_equal(u.trajectory.n_frames, 200) u.trajectory[199] - assert_array_almost_equal( - u.atoms.positions[0], [1.7240, 11.2730, 14.1200] - ) + assert_array_almost_equal(u.atoms.positions[0], [1.7240, 11.2730, 14.1200]) def test_read_statusbit(self): u = Universe(mol2_ligand) @@ -113,9 +111,7 @@ def test_comments_header(self): assert_equal(len(u.atoms), 9) assert_equal(u.trajectory.n_frames, 2) u.trajectory[1] - assert_array_almost_equal( - u.atoms.positions[2], [-12.2710, -1.9540, -16.0480] - ) + assert_array_almost_equal(u.atoms.positions[2], [-12.2710, -1.9540, -16.0480]) def test_no_bonds(self, tmpdir): # Issue #3057 @@ -163,9 +159,7 @@ def test_slice_traj(self): def test_reverse_traj(self): frames = [ts.frame for ts in self.traj[20:5:-1]] - assert_equal( - frames, list(range(20, 5, -1)), "reversing traj [20:5:-1]" - ) + assert_equal(frames, list(range(20, 5, -1)), "reversing traj [20:5:-1]") def test_n_frames(self): assert_equal( diff --git a/testsuite/MDAnalysisTests/coordinates/test_netcdf.py b/testsuite/MDAnalysisTests/coordinates/test_netcdf.py index 1ebad11665..0f84a386e6 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_netcdf.py +++ b/testsuite/MDAnalysisTests/coordinates/test_netcdf.py @@ -79,9 +79,7 @@ def test_get_writer(self, universe): assert w.remarks.startswith("AMBER NetCDF format") def test_get_writer_custom_n_atoms(self, universe): - with universe.trajectory.Writer( - "out.ncdf", n_atoms=42, remarks="Hi!" - ) as w: + with universe.trajectory.Writer("out.ncdf", n_atoms=42, remarks="Hi!") as w: assert w.n_atoms == 42 assert w.remarks == "Hi!" @@ -341,9 +339,7 @@ def test_velocities(self, universe, index, expected): @pytest.mark.parametrize("index,expected", ((0, 1.0), (8, 9.0))) def test_time(self, universe, index, expected): - assert_almost_equal( - expected, universe.trajectory[index].time, self.prec - ) + assert_almost_equal(expected, universe.trajectory[index].time, self.prec) def test_nframes(self, universe): assert_equal(10, universe.trajectory.n_frames) @@ -427,16 +423,12 @@ def create_ncdf(self, params): time = ncdf.createVariable("time", "d", ("time",)) setattr(time, "units", params["time"]) time[:] = 1.0 - cell_spatial = ncdf.createVariable( - "cell_spatial", "c", ("cell_spatial",) - ) + cell_spatial = ncdf.createVariable("cell_spatial", "c", ("cell_spatial",)) cell_spatial[:] = np.asarray(list("abc")) cell_angular = ncdf.createVariable( "cell_angular", "c", ("cell_angular", "label") ) - cell_angular[:] = np.asarray( - [list("alpha"), list("beta "), list("gamma")] - ) + cell_angular[:] = np.asarray([list("alpha"), list("beta "), list("gamma")]) # Spatial or atom dependent variables if (params["spatial"]) and (params["n_atoms"]): @@ -473,9 +465,7 @@ def create_ncdf(self, params): velocs = ncdf.createVariable( "velocities", "f8", ("atom", "spatial") ) - forces = ncdf.createVariable( - "forces", "f8", ("atom", "spatial") - ) + forces = ncdf.createVariable("forces", "f8", ("atom", "spatial")) # Set units if params["coordinates"]: @@ -509,18 +499,10 @@ def create_ncdf(self, params): coords[:] = np.asarray( range(params["spatial"]), dtype=np.float32 ) - cell_lengths[:] = np.array( - [20.0, 20.0, 20.0], dtype=np.float32 - ) - cell_angles[:] = np.array( - [90.0, 90.0, 90.0], dtype=np.float32 - ) - velocs[:] = np.asarray( - range(params["spatial"]), dtype=np.float32 - ) - forces[:] = np.asarray( - range(params["spatial"]), dtype=np.float32 - ) + cell_lengths[:] = np.array([20.0, 20.0, 20.0], dtype=np.float32) + cell_angles[:] = np.array([90.0, 90.0, 90.0], dtype=np.float32) + velocs[:] = np.asarray(range(params["spatial"]), dtype=np.float32) + forces[:] = np.asarray(range(params["spatial"]), dtype=np.float32) # self.scale_factor overrides which variable gets a scale_factor if params["scale_factor"]: @@ -710,14 +692,11 @@ def test_conventionversion_warn(self, tmpdir): assert len(record) == 1 wmsg = ( - "NCDF trajectory format is 2.0 but the reader " - "implements format 1.0" + "NCDF trajectory format is 2.0 but the reader " "implements format 1.0" ) assert str(record[0].message.args[0]) == wmsg - @pytest.mark.parametrize( - "mutation", [{"program": None}, {"programVersion": None}] - ) + @pytest.mark.parametrize("mutation", [{"program": None}, {"programVersion": None}]) def test_program_warn(self, tmpdir, mutation): params = self.gen_params(keypair=mutation, restart=False) with tmpdir.as_cwd(): @@ -791,14 +770,12 @@ def _test_write_trajectory(self, universe, outfile): assert_equal( coords[:].dtype.name, np.dtype(np.float32).name, - err_msg="ncdf coord output not float32 " - "but {}".format(coords[:].dtype), + err_msg="ncdf coord output not float32 " "but {}".format(coords[:].dtype), ) assert_equal( time[:].dtype.name, np.dtype(np.float32).name, - err_msg="ncdf time output not float32 " - "but {}".format(time[:].dtype), + err_msg="ncdf time output not float32 " "but {}".format(time[:].dtype), ) def test_write_trajectory_netCDF4(self, universe, outfile): @@ -842,16 +819,14 @@ def _check_new_traj(self, universe, outfile): self.prec, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" - % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), ) # not a good test because in the example trajectory all times are 0 assert_almost_equal( orig_ts.time, written_ts.time, self.prec, - err_msg="Time for step {0} are not the " - "same.".format(orig_ts.frame), + err_msg="Time for step {0} are not the " "same.".format(orig_ts.frame), ) assert_almost_equal( written_ts.dimensions, @@ -892,15 +867,13 @@ def _check_new_traj(self, universe, outfile): v[:], v_new[:], self.prec, - err_msg="Variable '{0}' not " - "written correctly".format(k), + err_msg="Variable '{0}' not " "written correctly".format(k), ) except TypeError: assert_equal( v[:], v_new[:], - err_msg="Variable {0} not written " - "correctly".format(k), + err_msg="Variable {0} not written " "correctly".format(k), ) def test_TRR2NCDF(self, outfile): @@ -938,8 +911,7 @@ def test_TRR2NCDF(self, outfile): orig_ts.time, written_ts.time, self.prec, - err_msg="Time for step {0} are not the " - "same.".format(orig_ts.frame), + err_msg="Time for step {0} are not the " "same.".format(orig_ts.frame), ) assert_almost_equal( written_ts.dimensions, @@ -967,15 +939,13 @@ def test_write_AtomGroup(self, universe, outfile, outtop): self.prec, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" - % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), ) assert_almost_equal( orig_ts.time, written_ts.time, self.prec, - err_msg="Time for step {0} are not the " - "same.".format(orig_ts.frame), + err_msg="Time for step {0} are not the " "same.".format(orig_ts.frame), ) assert_almost_equal( written_ts.dimensions, @@ -1057,18 +1027,14 @@ def test_write_u(self, pos, vel, force, tmpdir, u1, u2): u = mda.Universe(self.top, outfile) # check the trajectory contents match reference universes - for ts, ref_ts in zip( - u.trajectory, [u1.trajectory.ts, u2.trajectory.ts] - ): + for ts, ref_ts in zip(u.trajectory, [u1.trajectory.ts, u2.trajectory.ts]): if pos: assert_almost_equal(ts._pos, ref_ts._pos, self.prec) else: with pytest.raises(mda.NoDataError): getattr(ts, "positions") if vel: - assert_almost_equal( - ts._velocities, ref_ts._velocities, self.prec - ) + assert_almost_equal(ts._velocities, ref_ts._velocities, self.prec) else: with pytest.raises(mda.NoDataError): getattr(ts, "velocities") @@ -1229,15 +1195,11 @@ def test_write_read_write( for ts1, ts3 in zip(universe.trajectory, universe3.trajectory): assert_almost_equal(ts1.time, ts3.time) assert_almost_equal(ts1.dimensions, ts3.dimensions) - assert_almost_equal( - universe.atoms.positions, universe3.atoms.positions, 4 - ) + assert_almost_equal(universe.atoms.positions, universe3.atoms.positions, 4) assert_almost_equal( universe.atoms.velocities, universe3.atoms.velocities, 4 ) - assert_almost_equal( - universe.atoms.forces, universe3.atoms.forces, 4 - ) + assert_almost_equal(universe.atoms.forces, universe3.atoms.forces, 4) class TestScipyScaleFactors(TestNCDFWriterScaleFactors): @@ -1246,9 +1208,7 @@ class TestScipyScaleFactors(TestNCDFWriterScaleFactors): @pytest.fixture(autouse=True) def block_netcdf4(self, monkeypatch): - monkeypatch.setattr( - sys.modules["MDAnalysis.coordinates.TRJ"], "netCDF4", None - ) + monkeypatch.setattr(sys.modules["MDAnalysis.coordinates.TRJ"], "netCDF4", None) def test_ncdf4_not_present(self, outfile, universe): # whilst we're here, let's also test this warning diff --git a/testsuite/MDAnalysisTests/coordinates/test_pdb.py b/testsuite/MDAnalysisTests/coordinates/test_pdb.py index 9c88b97ffd..9ef3c52d3c 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_pdb.py +++ b/testsuite/MDAnalysisTests/coordinates/test_pdb.py @@ -64,9 +64,7 @@ assert_allclose, ) -IGNORE_NO_INFORMATION_WARNING = ( - "ignore:Found no information for attr:UserWarning" -) +IGNORE_NO_INFORMATION_WARNING = "ignore:Found no information for attr:UserWarning" @pytest.fixture @@ -116,8 +114,7 @@ def test_ENT(self): class TestPDBMetadata(object): header = "HYDROLASE 11-MAR-12 4E43" title = [ - "HIV PROTEASE (PR) DIMER WITH ACETATE IN EXO SITE AND PEPTIDE " - "IN ACTIVE", + "HIV PROTEASE (PR) DIMER WITH ACETATE IN EXO SITE AND PEPTIDE " "IN ACTIVE", "2 SITE", ] compnd = [ @@ -165,9 +162,7 @@ def test_TITLE(self, universe): len(self.title), err_msg="TITLE does not contain same number of lines", ) - for lineno, (parsed, reference) in enumerate( - zip(title, self.title), start=1 - ): + for lineno, (parsed, reference) in enumerate(zip(title, self.title), start=1): assert_equal( parsed, reference, @@ -178,9 +173,7 @@ def test_COMPND(self, universe): try: compound = universe.trajectory.compound except AttributeError: - raise AssertionError( - "Reader does not have a 'compound' attribute." - ) + raise AssertionError("Reader does not have a 'compound' attribute.") assert_equal( len(compound), len(self.compnd), @@ -207,9 +200,7 @@ def test_REMARK(self, universe): ) # only look at the first 5 entries for lineno, (parsed, reference) in enumerate( - zip( - remarks[: self.nmax_remarks], self.remarks[: self.nmax_remarks] - ), + zip(remarks[: self.nmax_remarks], self.remarks[: self.nmax_remarks]), start=1, ): assert_equal( @@ -223,9 +214,7 @@ class TestExtendedPDBReader(_SingleFrameReader): __test__ = True def setUp(self): - self.universe = mda.Universe( - PDB_small, topology_format="XPDB", format="XPDB" - ) + self.universe = mda.Universe(PDB_small, topology_format="XPDB", format="XPDB") # 3 decimals in PDB spec # http://www.wwpdb.org/documentation/format32/sect9.html#ATOM self.prec = 3 @@ -277,9 +266,7 @@ def universe_and_expected_dims(self, request): @pytest.fixture def outfile(self, tmpdir): - return str( - tmpdir.mkdir("PDBWriter").join("primitive-pdb-writer" + self.ext) - ) + return str(tmpdir.mkdir("PDBWriter").join("primitive-pdb-writer" + self.ext)) @pytest.fixture def u_no_ids(self): @@ -298,9 +285,7 @@ def u_no_ids(self): trajectory=True, ) universe.add_TopologyAttr("icodes", [" "] * len(universe.residues)) - universe.add_TopologyAttr( - "record_types", ["ATOM"] * len(universe.atoms) - ) + universe.add_TopologyAttr("record_types", ["ATOM"] * len(universe.atoms)) universe.dimensions = [10, 10, 10, 90, 90, 90] return universe @@ -407,8 +392,7 @@ def test_write_single_frame_AtomGroup(self, universe2, outfile): u.atoms.positions, self.prec, err_msg="Written coordinates do not " - "agree with original coordinates from frame %d" - % u.trajectory.frame, + "agree with original coordinates from frame %d" % u.trajectory.frame, ) def test_write_nodims(self, universe_and_expected_dims, outfile): @@ -428,7 +412,9 @@ def test_write_nodims(self, universe_and_expected_dims, outfile): else: assert np.allclose(u.dimensions, expected_dims) - expected_msg = "Unit cell dimensions not found. CRYST1 record set to unitary values." + expected_msg = ( + "Unit cell dimensions not found. CRYST1 record set to unitary values." + ) with pytest.warns(UserWarning, match=expected_msg): u.atoms.write(outfile) @@ -451,8 +437,7 @@ def test_write_nodims(self, universe_and_expected_dims, outfile): uout.atoms.positions, self.prec, err_msg="Written coordinates do not " - "agree with original coordinates from frame %d" - % u.trajectory.frame, + "agree with original coordinates from frame %d" % u.trajectory.frame, ) def test_check_coordinate_limits_min(self, universe, outfile): @@ -495,9 +480,7 @@ def test_check_HEADER_TITLE_multiframe(self, universe2, outfile): assert got_title <= 1, "There should be only one TITLE." @pytest.mark.parametrize("startframe,maxframes", [(0, 12), (9997, 12)]) - def test_check_MODEL_multiframe( - self, universe2, outfile, startframe, maxframes - ): + def test_check_MODEL_multiframe(self, universe2, outfile, startframe, maxframes): """Check whether MODEL number is in the right column (Issue #1950)""" u = universe2 protein = u.select_atoms("protein and name CA") @@ -567,18 +550,12 @@ def test_hetatm_written(self, universe4, tmpdir, outfile): u.atoms.write(outfile) written = mda.Universe(outfile) - written_atoms = written.select_atoms( - "resname ETA and " "record_type HETATM" - ) + written_atoms = written.select_atoms("resname ETA and " "record_type HETATM") assert len(u_hetatms) == len(written_atoms), "mismatched HETATM number" - assert_almost_equal( - u_hetatms.atoms.positions, written_atoms.atoms.positions - ) + assert_almost_equal(u_hetatms.atoms.positions, written_atoms.atoms.positions) - def test_default_atom_record_type_written( - self, universe5, tmpdir, outfile - ): + def test_default_atom_record_type_written(self, universe5, tmpdir, outfile): """ Checks that ATOM record types are written when there is no record_type attribute. @@ -1025,9 +1002,7 @@ def universe(): def test_load_pdb(self, universe): U = universe - assert_equal( - len(U.atoms), self.ref_n_atoms, "load Universe from big PDB" - ) + assert_equal(len(U.atoms), self.ref_n_atoms, "load Universe from big PDB") assert_equal( U.atoms.select_atoms("resid 150 and name HA2").atoms[0], U.atoms[self.ref_E151HA2_index], @@ -1323,9 +1298,9 @@ def test_deduce_PDB_atom_name(atom, refname): # The Pair named tuple is used to mock atoms as we only need them to have a # ``resname`` and a ``name`` attribute. dummy_file = StringIO() - name = mda.coordinates.PDB.PDBWriter( - dummy_file, n_atoms=1 - )._deduce_PDB_atom_name(atom.name, atom.resname) + name = mda.coordinates.PDB.PDBWriter(dummy_file, n_atoms=1)._deduce_PDB_atom_name( + atom.name, atom.resname + ) assert_equal(name, refname) @@ -1365,9 +1340,7 @@ def test_len(self, pdbfile): def test_order(self, pdbfile): u = mda.Universe(pdbfile) - for ts, refbox, refpos in zip( - u.trajectory, self.boxsize, self.position - ): + for ts, refbox, refpos in zip(u.trajectory, self.boxsize, self.position): assert_almost_equal(u.dimensions[0], refbox) assert_almost_equal(u.atoms[0].position[0], refpos) @@ -1411,9 +1384,7 @@ def test_write_pdb_zero_atoms(tmpdir): def test_atom_not_match(tmpdir): # issue 1998 - outfile = str( - tmpdir.mkdir("PDBReader").join("test_atom_not_match" + ".pdb") - ) + outfile = str(tmpdir.mkdir("PDBReader").join("test_atom_not_match" + ".pdb")) u = mda.Universe(PSF, DCD) # select two groups of atoms protein = u.select_atoms("protein and name CA") @@ -1437,11 +1408,7 @@ def test_partially_missing_cryst(): # mangle the cryst lines so that only box angles are left # this mimics '6edu' from PDB raw = [ - ( - line - if not line.startswith("CRYST") - else line[:6] + " " * 28 + line[34:] - ) + (line if not line.startswith("CRYST") else line[:6] + " " * 28 + line[34:]) for line in raw ] @@ -1463,9 +1430,7 @@ def test_write_no_atoms_elements(dummy_universe_without_elements): writer.write(dummy_universe_without_elements.atoms) content = destination.getvalue() element_symbols = [ - line[76:78].strip() - for line in content.splitlines() - if line[:6] == "ATOM " + line[76:78].strip() for line in content.splitlines() if line[:6] == "ATOM " ] expectation = ["", "", "", "", ""] assert element_symbols == expectation @@ -1487,9 +1452,7 @@ def test_write_atom_elements(dummy_universe_without_elements): writer.write(dummy_universe_without_elements.atoms) content = destination.getvalue() element_symbols = [ - line[76:78].strip() - for line in content.splitlines() - if line[:6] == "ATOM " + line[76:78].strip() for line in content.splitlines() if line[:6] == "ATOM " ] assert element_symbols == expectation @@ -1513,9 +1476,7 @@ def test_elements_roundtrip(tmpdir): def test_cryst_meaningless_warning(): # issue 2599 # FIXME: This message might change with Issue #2698 - with pytest.warns( - UserWarning, match="Unit cell dimensions will be set to None." - ): + with pytest.warns(UserWarning, match="Unit cell dimensions will be set to None."): mda.Universe(PDB_CRYOEM_BOX) @@ -1588,9 +1549,7 @@ def test_read_segids(): ATOM 665 OG1 THR A 315 21.047 13.922 1.304 1.00 15.14 B O """ - u_invalid_segid = mda.Universe( - StringIO(invalid_seg_format_str), format="PDB" - ) + u_invalid_segid = mda.Universe(StringIO(invalid_seg_format_str), format="PDB") u_acceptable = mda.Universe(StringIO(acceptable_format_str), format="PDB") u_standard = mda.Universe(StringIO(standard_format_str), format="PDB") @@ -1598,9 +1557,7 @@ def test_read_segids(): # Thus, segids existed and were set to "B" for all atoms. # After version 2.10.0, segid is read from column 73-76. # segid is expected to set by chainID "A" for all atoms. - assert_equal( - u_invalid_segid.atoms.segids, ["A"] * len(u_invalid_segid.atoms) - ) + assert_equal(u_invalid_segid.atoms.segids, ["A"] * len(u_invalid_segid.atoms)) # Before version 2.10.0, segid was set to read from column 67-76. # Due to misalignment in b-factor column, diff --git a/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py b/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py index 06bc62830b..c358f77570 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py +++ b/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py @@ -79,9 +79,7 @@ def test_neighborhood(self, universe): assert_equal(len(residue_neighbors), 80) def test_n_frames(self, universe): - assert_equal( - universe.trajectory.n_frames, 1, "wrong number of frames in pdb" - ) + assert_equal(universe.trajectory.n_frames, 1, "wrong number of frames in pdb") def test_time(self, universe): assert_equal(universe.trajectory.time, 0.0, "wrong time of the frame") diff --git a/testsuite/MDAnalysisTests/coordinates/test_pqr.py b/testsuite/MDAnalysisTests/coordinates/test_pqr.py index fc69337ddb..9f6798c5b9 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_pqr.py +++ b/testsuite/MDAnalysisTests/coordinates/test_pqr.py @@ -93,9 +93,7 @@ def universe(): prec = 3 - @pytest.mark.parametrize( - "filename", ["test.pqr", "test.pqr.bz2", "test.pqr.gz"] - ) + @pytest.mark.parametrize("filename", ["test.pqr", "test.pqr.bz2", "test.pqr.gz"]) def test_simple_writer_roundtrip(self, universe, filename, tmpdir): with tmpdir.as_cwd(): universe.atoms.write(filename) diff --git a/testsuite/MDAnalysisTests/coordinates/test_reader_api.py b/testsuite/MDAnalysisTests/coordinates/test_reader_api.py index 4ae5c0f5c6..9094e22588 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_reader_api.py +++ b/testsuite/MDAnalysisTests/coordinates/test_reader_api.py @@ -103,9 +103,7 @@ def test_required_attributes(self, reader): "units", "format", ]: - assert_equal( - hasattr(reader, attr), True, "Missing attr: {0}".format(attr) - ) + assert_equal(hasattr(reader, attr), True, "Missing attr: {0}".format(attr)) def test_iter(self, reader): l = [ts for ts in reader] diff --git a/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py b/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py index 1b2bc468b3..781d4866aa 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py +++ b/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py @@ -175,9 +175,7 @@ def test_volume(self, ts): assert_equal(ts.volume, self.ref_volume) def test_triclinic_vectors(self, ts): - assert_allclose( - ts.triclinic_dimensions, triclinic_vectors(ts.dimensions) - ) + assert_allclose(ts.triclinic_dimensions, triclinic_vectors(ts.dimensions)) def test_set_triclinic_vectors(self, ts): ref_vec = triclinic_vectors(self.newbox) @@ -406,9 +404,7 @@ def _check_copy(self, name, ref_ts): """Check basic copy""" ts2 = ref_ts.copy() - err_msg = ( - "Timestep copy failed for format {form}" " on attribute {att}" - ) + err_msg = "Timestep copy failed for format {form}" " on attribute {att}" # eq method checks: # - frame @@ -417,9 +413,7 @@ def _check_copy(self, name, ref_ts): assert ref_ts == ts2 if not ref_ts.dimensions is None: - assert_array_almost_equal( - ref_ts.dimensions, ts2.dimensions, decimal=4 - ) + assert_array_almost_equal(ref_ts.dimensions, ts2.dimensions, decimal=4) else: assert ref_ts.dimensions == ts2.dimensions @@ -511,9 +505,7 @@ def test_copy(self, func, ts): ts = u.trajectory.ts func(self, self.name, ts) - @pytest.fixture( - params=filter(any, itertools.product([True, False], repeat=3)) - ) + @pytest.fixture(params=filter(any, itertools.product([True, False], repeat=3))) def some_ts(self, request): p, v, f = request.param return self._from_coords(p, v, f) @@ -719,9 +711,7 @@ class TestBaseTimestepInterface(object): ) ) def universe(self, request): - topology, trajectory, trajectory_format, topology_format = ( - request.param - ) + topology, trajectory, trajectory_format, topology_format = request.param if trajectory_format is not None and topology_format is not None: return mda.Universe( topology, diff --git a/testsuite/MDAnalysisTests/coordinates/test_tng.py b/testsuite/MDAnalysisTests/coordinates/test_tng.py index 8eaa64d5ec..905f612bc4 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_tng.py +++ b/testsuite/MDAnalysisTests/coordinates/test_tng.py @@ -241,9 +241,7 @@ def test_initial_frame_is_0(self, universe): assert_equal( universe.trajectory.ts.frame, 0, - "initial frame is not 0 but {0}".format( - universe.trajectory.ts.frame - ), + "initial frame is not 0 but {0}".format(universe.trajectory.ts.frame), ) def test_starts_with_first_frame(self, universe): @@ -255,9 +253,7 @@ def test_rewind(self, universe): trj = universe.trajectory trj.next() trj.next() # for readers that do not support indexing - assert_equal( - trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)" - ) + assert_equal(trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)") trj.rewind() assert_equal(trj.ts.frame, 0, "failed to rewind to first frame") assert np.any(universe.atoms.positions > 0) @@ -293,9 +289,7 @@ def test_positions_first_frame(self, universe): def test_box_first_frame(self, universe): dims = universe.trajectory[0].dimensions - assert_allclose( - dims, triclinic_box(*self._box_frame_0), rtol=10**-self.prec - ) + assert_allclose(dims, triclinic_box(*self._box_frame_0), rtol=10**-self.prec) def test_positions_last_frame(self, universe): pos = universe.trajectory[100].positions @@ -307,9 +301,7 @@ def test_positions_last_frame(self, universe): def test_box_last_frame(self, universe): dims = universe.trajectory[100].dimensions - assert_allclose( - dims, triclinic_box(*self._box_frame_100), rtol=10**-self.prec - ) + assert_allclose(dims, triclinic_box(*self._box_frame_100), rtol=10**-self.prec) @pytest.mark.parametrize("frame", [0, 20, 50, 100]) def test_step(self, universe, frame): @@ -321,29 +313,21 @@ def test_lambda_in_ts(self, universe): ts = universe.trajectory[10] assert "TNG_GMX_LAMBDA" in ts.data.keys() assert isinstance(ts.data["TNG_GMX_LAMBDA"], np.ndarray) - assert_equal( - ts.data["TNG_GMX_LAMBDA"], np.asarray([[0]], dtype=np.float32) - ) + assert_equal(ts.data["TNG_GMX_LAMBDA"], np.asarray([[0]], dtype=np.float32)) def test_read_box_fail_strange_step(self, universe): stepnum = 123 # step number with no data iterator_step = universe.trajectory._file_iterator.read_step(stepnum) with pytest.raises(IOError, match="Failed to read box from TNG file"): - universe.trajectory._frame_to_ts( - iterator_step, universe.trajectory.ts - ) + universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) def test_read_pos_fail_strange_step(self, universe): stepnum = 123 # step number with no data iterator_step = universe.trajectory._file_iterator.read_step(stepnum) # set _has_box to False to trigger position reading error universe.trajectory._has_box = False - with pytest.raises( - IOError, match="Failed to read positions from TNG file" - ): - universe.trajectory._frame_to_ts( - iterator_step, universe.trajectory.ts - ) + with pytest.raises(IOError, match="Failed to read positions from TNG file"): + universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) def test_additional_block_read_fails(self, universe): stepnum = 123 # step number with no data @@ -355,9 +339,7 @@ def test_additional_block_read_fails(self, universe): with pytest.raises( IOError, match="Failed to read additional block TNG_GMX_LAMBDA" ): - universe.trajectory._frame_to_ts( - iterator_step, universe.trajectory.ts - ) + universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) def test_parse_n_atoms(self, universe): assert universe.trajectory.parse_n_atoms(TNG_traj) == self._n_atoms @@ -412,12 +394,8 @@ def test_read_vels_fail_strange_step(self, universe): # set _has_* attrs to False to trigger velocities reading error universe.trajectory._has_box = False universe.trajectory._has_positions = False - with pytest.raises( - IOError, match="Failed to read velocities from TNG file" - ): - universe.trajectory._frame_to_ts( - iterator_step, universe.trajectory.ts - ) + with pytest.raises(IOError, match="Failed to read velocities from TNG file"): + universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) def test_read_force_fail_strange_step(self, universe): stepnum = 123 # step number with no data @@ -426,12 +404,8 @@ def test_read_force_fail_strange_step(self, universe): universe.trajectory._has_box = False universe.trajectory._has_positions = False universe.trajectory._has_velocities = False - with pytest.raises( - IOError, match="Failed to read forces from TNG file" - ): - universe.trajectory._frame_to_ts( - iterator_step, universe.trajectory.ts - ) + with pytest.raises(IOError, match="Failed to read forces from TNG file"): + universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) @pytest.mark.skipif(not HAS_PYTNG, reason="pytng not installed") diff --git a/testsuite/MDAnalysisTests/coordinates/test_trc.py b/testsuite/MDAnalysisTests/coordinates/test_trc.py index 5069fe3ed3..f9fde47aa3 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_trc.py +++ b/testsuite/MDAnalysisTests/coordinates/test_trc.py @@ -53,9 +53,7 @@ def test_trc_positions(self, TRC_U): ) # fith frame first particle TRC_U.trajectory[4] - assert_allclose( - TRC_U.atoms.positions[0], [0.37026654, 22.78805010, 3.69695262] - ) + assert_allclose(TRC_U.atoms.positions[0], [0.37026654, 22.78805010, 3.69695262]) def test_trc_dimensions(self, TRC_U): assert TRC_U.trajectory[0].dimensions is None @@ -96,13 +94,9 @@ def test_rewind(self, TRC_U): trc.next() trc.next() trc.next() - assert ( - trc.ts.frame == 4 - ), "trajectory.next() did not forward to frameindex 4" + assert trc.ts.frame == 4, "trajectory.next() did not forward to frameindex 4" trc.rewind() - assert ( - trc.ts.frame == 0 - ), "trajectory.rewind() failed to rewind to first frame" + assert trc.ts.frame == 0, "trajectory.rewind() failed to rewind to first frame" assert np.any( TRC_U.atoms.positions != 0 @@ -221,14 +215,8 @@ def test_trc_distances(self, TRC_U): ag1 = atom_1a + atom_1b + atom_1c + atom_1d ag2 = atom_2a + atom_2b + atom_2c + atom_2d - dist_A = distances.dist(ag1, ag2, box=ts.dimensions)[ - 2 - ] # return distance - dist_B = ( - atomicdistances.AtomicDistances(ag1, ag2, pbc=True) - .run() - .results[0] - ) + dist_A = distances.dist(ag1, ag2, box=ts.dimensions)[2] # return distance + dist_B = atomicdistances.AtomicDistances(ag1, ag2, pbc=True).run().results[0] assert_allclose( dist_A, [5.9488481, 4.4777278, 20.8165518, 7.5727112], rtol=1e-06 @@ -246,9 +234,7 @@ def test_universe(self): class TestTRCGenboxOrigin: def test_universe(self): - with pytest.raises( - ValueError, match="doesnt't support a shifted origin!" - ): + with pytest.raises(ValueError, match="doesnt't support a shifted origin!"): mda.Universe(TRC_PDB_VAC, TRC_GENBOX_ORIGIN) @@ -265,9 +251,7 @@ class TestTRCEmptyFile: def test_universe(self): with pytest.raises( ValueError, - match=( - "No supported blocks were found within the GROMOS trajectory!" - ), + match=("No supported blocks were found within the GROMOS trajectory!"), ): mda.Universe(TRC_PDB_VAC, TRC_EMPTY) @@ -306,16 +290,12 @@ def test_trc_n_frames(self, TRC_U): assert TRC_U.trajectory.n_frames == 3 def test_trc_frame(self, TRC_U): - with pytest.warns( - UserWarning, match="POSITION block is not supported!" - ): + with pytest.warns(UserWarning, match="POSITION block is not supported!"): assert TRC_U.trajectory[0].frame == 0 assert TRC_U.trajectory[2].frame == 2 def test_trc_time(self, TRC_U): - with pytest.warns( - UserWarning, match="POSITION block is not supported!" - ): + with pytest.warns(UserWarning, match="POSITION block is not supported!"): assert TRC_U.trajectory[0].time == 0 assert TRC_U.trajectory[2].time == 0 diff --git a/testsuite/MDAnalysisTests/coordinates/test_trj.py b/testsuite/MDAnalysisTests/coordinates/test_trj.py index 65c1e62dba..b6de892335 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_trj.py +++ b/testsuite/MDAnalysisTests/coordinates/test_trj.py @@ -69,24 +69,19 @@ def test_amber_proteinselection(self, universe): def test_sum_centres_of_geometry(self, universe): protein = universe.select_atoms("protein") - total = np.sum( - [protein.center_of_geometry() for ts in universe.trajectory] - ) + total = np.sum([protein.center_of_geometry() for ts in universe.trajectory]) assert_almost_equal( total, self.ref_sum_centre_of_geometry, self.prec, - err_msg="sum of centers of geometry over the " - "trajectory do not match", + err_msg="sum of centers of geometry over the " "trajectory do not match", ) def test_initial_frame_is_0(self, universe): assert_equal( universe.trajectory.ts.frame, 0, - "initial frame is not 0 but {0}".format( - universe.trajectory.ts.frame - ), + "initial frame is not 0 but {0}".format(universe.trajectory.ts.frame), ) def test_starts_with_first_frame(self, universe): @@ -100,9 +95,7 @@ def test_rewind(self, universe): trj = universe.trajectory trj.next() trj.next() # for readers that do not support indexing - assert_equal( - trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)" - ) + assert_equal(trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)") trj.rewind() assert_equal(trj.ts.frame, 0, "failed to rewind to first frame") assert np.any(universe.atoms.positions > 0), ( diff --git a/testsuite/MDAnalysisTests/coordinates/test_trz.py b/testsuite/MDAnalysisTests/coordinates/test_trz.py index 8e42bc644f..aef058a620 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_trz.py +++ b/testsuite/MDAnalysisTests/coordinates/test_trz.py @@ -60,16 +60,12 @@ def universe(self): def test_load_trz(self, universe): U = universe - assert_equal( - len(U.atoms), self.ref_n_atoms, "load Universe from PSF and TRZ" - ) + assert_equal(len(U.atoms), self.ref_n_atoms, "load Universe from PSF and TRZ") def test_next_trz(self, universe): assert_equal(universe.trajectory.ts.frame, 0, "starts at first frame") universe.trajectory.next() - assert_equal( - universe.trajectory.ts.frame, 1, "next returns frame index 1" - ) + assert_equal(universe.trajectory.ts.frame, 1, "next returns frame index 1") def test_rewind_trz(self, universe): # move to different frame and rewind to get first frame back @@ -155,9 +151,7 @@ def test_time(self, universe): ) def test_title(self, universe): - assert_equal( - self.ref_title, universe.trajectory.title, "wrong title in trz" - ) + assert_equal(self.ref_title, universe.trajectory.title, "wrong title in trz") def test_get_writer(self, universe, tmpdir): self.outfile = os.path.join(str(tmpdir), "test-trz-writer.trz") @@ -260,9 +254,7 @@ def test_no_box_warning(self, outfile): u = mda.Universe.empty(10, trajectory=True) u.dimensions = None - with pytest.warns( - UserWarning, match="box will be written as all zero values" - ): + with pytest.warns(UserWarning, match="box will be written as all zero values"): with mda.Writer(outfile, n_atoms=10) as w: w.write(u.atoms) diff --git a/testsuite/MDAnalysisTests/coordinates/test_txyz.py b/testsuite/MDAnalysisTests/coordinates/test_txyz.py index 66cd38067e..770af1a8a1 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_txyz.py +++ b/testsuite/MDAnalysisTests/coordinates/test_txyz.py @@ -44,23 +44,17 @@ def ARC_PBC_U(): def test_txyz_positions(TXYZ_U): - assert_almost_equal( - TXYZ_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000] - ) + assert_almost_equal(TXYZ_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000]) def test_arc_positions(ARC_U): - assert_almost_equal( - ARC_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000] - ) + assert_almost_equal(ARC_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000]) def test_arc_positions_frame_2(ARC_U): ARC_U.trajectory[1] - assert_almost_equal( - ARC_U.atoms.positions[0], [-0.231579, -0.350841, -0.037475] - ) + assert_almost_equal(ARC_U.atoms.positions[0], [-0.231579, -0.350841, -0.037475]) def test_arc_traj_length(ARC_U): diff --git a/testsuite/MDAnalysisTests/coordinates/test_writer_api.py b/testsuite/MDAnalysisTests/coordinates/test_writer_api.py index 4c3ac08cb5..d7f55a6b89 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_writer_api.py +++ b/testsuite/MDAnalysisTests/coordinates/test_writer_api.py @@ -28,8 +28,7 @@ # grab all known writers # sort so test order is predictable for parallel tests writers = sorted( - set(mda._MULTIFRAME_WRITERS.values()) - | set(mda._SINGLEFRAME_WRITERS.values()), + set(mda._MULTIFRAME_WRITERS.values()) | set(mda._SINGLEFRAME_WRITERS.values()), key=lambda x: x.__name__, ) known_ts_haters = [ @@ -55,8 +54,7 @@ def test_ts_error(writer, tmpdir): elif writer == mda.coordinates.LAMMPS.DATAWriter: pytest.skip("DATAWriter requires integer atom types") elif ( - writer == mda.coordinates.H5MD.H5MDWriter - and not mda.coordinates.H5MD.HAS_H5PY + writer == mda.coordinates.H5MD.H5MDWriter and not mda.coordinates.H5MD.HAS_H5PY ): pytest.skip("skipping H5MDWriter test because h5py is not installed") else: @@ -89,8 +87,7 @@ def test_write_with_atomgroup(writer, tmpdir): elif writer == mda.coordinates.LAMMPS.DATAWriter: pytest.skip("DATAWriter requires integer atom types") elif ( - writer == mda.coordinates.H5MD.H5MDWriter - and not mda.coordinates.H5MD.HAS_H5PY + writer == mda.coordinates.H5MD.H5MDWriter and not mda.coordinates.H5MD.HAS_H5PY ): pytest.skip("skipping H5MDWriter test because h5py is not installed") else: @@ -118,8 +115,7 @@ def test_write_with_universe(writer, tmpdir): elif writer == mda.coordinates.LAMMPS.DATAWriter: pytest.skip("DATAWriter requires integer atom types") elif ( - writer == mda.coordinates.H5MD.H5MDWriter - and not mda.coordinates.H5MD.HAS_H5PY + writer == mda.coordinates.H5MD.H5MDWriter and not mda.coordinates.H5MD.HAS_H5PY ): pytest.skip("skipping H5MDWriter test because h5py is not installed") else: diff --git a/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py b/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py index 616bae0ef6..984799bfc2 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py +++ b/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py @@ -47,9 +47,7 @@ def test_default_multiframe(self): def test_singleframe(self): # check that singleframe=False has been respected - assert isinstance( - mda.Writer("this.magic", multiframe=False), self.MagicWriter - ) + assert isinstance(mda.Writer("this.magic", multiframe=False), self.MagicWriter) def test_multiframe_magic2(self): # this will work as we go for multiframe diff --git a/testsuite/MDAnalysisTests/coordinates/test_xdr.py b/testsuite/MDAnalysisTests/coordinates/test_xdr.py index 2a2f236924..a9631f17d2 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_xdr.py +++ b/testsuite/MDAnalysisTests/coordinates/test_xdr.py @@ -145,9 +145,7 @@ def test_jump_xdrtrj(self, universe): def test_jump_lastframe_xdrtrj(self, universe): universe.trajectory[-1] - assert_equal( - universe.coord.frame, 9, "indexing last frame with trajectory[-1]" - ) + assert_equal(universe.coord.frame, 9, "indexing last frame with trajectory[-1]") def test_slice_xdrtrj(self, universe): frames = [ts.frame for ts in universe.trajectory[2:9:3]] @@ -158,9 +156,7 @@ def test_reverse_xdrtrj(self, universe): assert_equal(frames, list(range(9, -1, -1)), "slicing xdrtrj [::-1]") def test_coordinates(self, universe): - ca_nm = np.array( - [[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32 - ) + ca_nm = np.array([[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32) # coordinates in the base unit (needed for True) ca_Angstrom = ca_nm * 10.0 universe.trajectory.rewind() @@ -275,9 +271,7 @@ def test_Writer(self, tmpdir, dt): assert_equal(u.trajectory.n_frames, 2) # prec = 6: TRR test fails; here I am generous and take self.prec = # 3... - assert_almost_equal( - u.atoms.positions, universe.atoms.positions, self.prec - ) + assert_almost_equal(u.atoms.positions, universe.atoms.positions, self.prec) if dt: # test total trajectory length assert_almost_equal( @@ -285,8 +279,7 @@ def test_Writer(self, tmpdir, dt): dt, 3, err_msg=( - "wrong total length of trajectory upon setting dt " - "explicitly" + "wrong total length of trajectory upon setting dt " "explicitly" ), ) @@ -367,8 +360,7 @@ def test_velocities(self, universe): universe.atoms.velocities[[47675, 47676]], v_base, self.prec, - err_msg="velocities for indices 47675,47676 do not " - "match known values", + err_msg="velocities for indices 47675,47676 do not " "match known values", ) for index, v_known in zip([47675, 47676], v_base): @@ -391,15 +383,11 @@ def universe(self): def test_coordinates(self, universe): # note: these are the native coordinates in nm - ca_nm = np.array( - [[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32 - ) + ca_nm = np.array([[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32) universe.trajectory.rewind() universe.trajectory.next() universe.trajectory.next() - assert_equal( - universe.trajectory.ts.frame, 2, "failed to step to frame 3" - ) + assert_equal(universe.trajectory.ts.frame, 2, "failed to step to frame 3") ca = universe.select_atoms("name CA and resid 122") # low precision match because we also look at the trr: only 3 decimals # in nm in xtc! @@ -444,9 +432,7 @@ def outfile(self, tmpdir): def test_write_trajectory(self, universe, Writer, outfile): """Test writing Gromacs trajectories (Issue 38)""" - with Writer( - outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt - ) as W: + with Writer(outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt) as W: for ts in universe.trajectory: W.write(universe) @@ -460,8 +446,7 @@ def test_write_trajectory(self, universe, Writer, outfile): 3, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" - % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), ) def test_timestep_not_modified_by_writer(self, universe, Writer, outfile): @@ -482,9 +467,7 @@ def test_timestep_not_modified_by_writer(self, universe, Writer, outfile): x, err_msg="Positions in Timestep were modified by writer.", ) - assert_equal( - ts.time, time, err_msg="Time in Timestep was modified by writer." - ) + assert_equal(ts.time, time, err_msg="Time in Timestep was modified by writer.") class TestXTCWriter(_GromacsWriter): @@ -497,9 +480,7 @@ class TestTRRWriter(_GromacsWriter): infilename = TRR def test_velocities(self, universe, Writer, outfile): - with Writer( - outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt - ) as W: + with Writer(outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt) as W: for ts in universe.trajectory: W.write(universe) @@ -513,16 +494,13 @@ def test_velocities(self, universe, Writer, outfile): 3, err_msg="velocities mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" - % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), ) def test_gaps(self, universe, Writer, outfile): """Tests the writing and reading back of TRRs with gaps in any of the coordinates/velocities properties.""" - with Writer( - outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt - ) as W: + with Writer(outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt) as W: for ts in universe.trajectory: # Inset some gaps in the properties: coords every 4 steps, vels # every 2. @@ -594,9 +572,7 @@ def test_data_preservation(self, universe, Writer, outfile): # check that each value is the same for k in orig_ts.data: - assert_allclose( - orig_ts.data[k], written_ts.data[k], err_msg=err_msg - ) + assert_allclose(orig_ts.data[k], written_ts.data[k], err_msg=err_msg) class _GromacsWriterIssue101(object): @@ -807,9 +783,7 @@ def test_lambda(self, ref, universe, tmpdir): reader = ref.reader(outfile) for i, ts in enumerate(reader): - assert_almost_equal( - ts.data["lambda"], i / float(reader.n_frames) - ) + assert_almost_equal(ts.data["lambda"], i / float(reader.n_frames)) class _GromacsReader_offsets(object): @@ -885,9 +859,7 @@ def test_nonexistent_offsets_file(self, traj): np_load_mock.side_effect = IOError with pytest.warns( UserWarning, - match=re.escape( - f"Failed to load offsets file {outfile_offsets}" - ), + match=re.escape(f"Failed to load offsets file {outfile_offsets}"), ): saved_offsets = XDR.read_numpy_offsets(outfile_offsets) assert saved_offsets == False @@ -900,9 +872,7 @@ def test_corrupted_offsets_file(self, traj): np_load_mock.side_effect = ValueError with pytest.warns( UserWarning, - match=re.escape( - f"Failed to load offsets file {outfile_offsets}" - ), + match=re.escape(f"Failed to load offsets file {outfile_offsets}"), ): saved_offsets = XDR.read_numpy_offsets(outfile_offsets) assert saved_offsets == False diff --git a/testsuite/MDAnalysisTests/core/test_accessors.py b/testsuite/MDAnalysisTests/core/test_accessors.py index 8084fa105a..cc59f11ddb 100644 --- a/testsuite/MDAnalysisTests/core/test_accessors.py +++ b/testsuite/MDAnalysisTests/core/test_accessors.py @@ -53,18 +53,13 @@ def test_convert_to_lib_method_kwargs(self, u): class TestAccessor: def test_access_from_class(self): - assert ( - mda.core.AtomGroup.convert_to - is mda.core.accessors.ConverterWrapper - ) + assert mda.core.AtomGroup.convert_to is mda.core.accessors.ConverterWrapper class TestConverterWrapper: def test_raises_valueerror(self): u = mda.Universe.empty(1) - with pytest.raises( - ValueError, match="No 'mdanalysis' converter found" - ): + with pytest.raises(ValueError, match="No 'mdanalysis' converter found"): u.atoms.convert_to("mdanalysis") @requires_rdkit diff --git a/testsuite/MDAnalysisTests/core/test_accumulate.py b/testsuite/MDAnalysisTests/core/test_accumulate.py index 2aa1fd2909..b43bf0b008 100644 --- a/testsuite/MDAnalysisTests/core/test_accumulate.py +++ b/testsuite/MDAnalysisTests/core/test_accumulate.py @@ -41,9 +41,7 @@ def group(self, request): return getattr(u, request.param) def test_accumulate_str_attribute(self, group): - assert_almost_equal( - group.accumulate("masses"), np.sum(group.atoms.masses) - ) + assert_almost_equal(group.accumulate("masses"), np.sum(group.atoms.masses)) def test_accumulate_different_func(self, group): assert_almost_equal( @@ -114,9 +112,7 @@ def test_accumulate_array_attribute_compounds(self, name, compound, level): for a in group.atoms.groupby(name).values() ] assert_equal( - group.accumulate( - np.ones((len(group.atoms), 2, 5)), compound=compound - ), + group.accumulate(np.ones((len(group.atoms), 2, 5)), compound=compound), ref, ) @@ -267,9 +263,7 @@ def test_dipole_moment_residues_com_coc(self, group): def test_dipole_moment_segment(self, methane): compound = "segments" - (_, _, n_compounds) = methane.atoms._split_by_compound_indices( - compound - ) + (_, _, n_compounds) = methane.atoms._split_by_compound_indices(compound) dipoles = methane.dipole_moment(compound=compound, unwrap=True) assert_almost_equal(dipoles, [0.0]) and len(dipoles) == n_compounds @@ -313,13 +307,9 @@ def test_quadrupole_moment_residues(self, group): def test_quadrupole_moment_segment(self, methane): compound = "segments" - (_, _, n_compounds) = methane.atoms._split_by_compound_indices( - compound - ) + (_, _, n_compounds) = methane.atoms._split_by_compound_indices(compound) quadrupoles = methane.quadrupole_moment(compound=compound, unwrap=True) - assert_almost_equal(quadrupoles, [0.0]) and len( - quadrupoles - ) == n_compounds + assert_almost_equal(quadrupoles, [0.0]) and len(quadrupoles) == n_compounds def test_quadrupole_moment_fragments(self, group): compound = "fragments" diff --git a/testsuite/MDAnalysisTests/core/test_atom.py b/testsuite/MDAnalysisTests/core/test_atom.py index 1d114c5a17..83080ce4b4 100644 --- a/testsuite/MDAnalysisTests/core/test_atom.py +++ b/testsuite/MDAnalysisTests/core/test_atom.py @@ -73,9 +73,7 @@ def test_setting_attributes_charge(self, atom): assert atom.charge == 6 def test_attributes_positions(self, atom): - known_pos = np.array( - [3.94543672, -12.4060812, -7.26820087], dtype=np.float32 - ) + known_pos = np.array([3.94543672, -12.4060812, -7.26820087], dtype=np.float32) a = atom # new position property (mutable) assert_almost_equal(a.position, known_pos) diff --git a/testsuite/MDAnalysisTests/core/test_atomgroup.py b/testsuite/MDAnalysisTests/core/test_atomgroup.py index 38432e65c4..99f05d7619 100644 --- a/testsuite/MDAnalysisTests/core/test_atomgroup.py +++ b/testsuite/MDAnalysisTests/core/test_atomgroup.py @@ -87,9 +87,7 @@ def test_improper(self, u): imp = ag.improper assert isinstance(imp, ImproperDihedral) - @pytest.mark.parametrize( - "btype,", ["bond", "angle", "dihedral", "improper"] - ) + @pytest.mark.parametrize("btype,", ["bond", "angle", "dihedral", "improper"]) def test_VE(self, btype, u): ag = u.atoms[:10] with pytest.raises(ValueError): @@ -135,9 +133,7 @@ def test_write_frames(self, u, tmpdir, frames): u.atoms.write(destination, frames=frames) u_new = mda.Universe(destination, to_guess=()) - new_positions = np.stack( - [ts.positions.copy() for ts in u_new.trajectory] - ) + new_positions = np.stack([ts.positions.copy() for ts in u_new.trajectory]) assert_array_almost_equal(new_positions, ref_positions) @@ -156,9 +152,7 @@ def test_write_frame_iterator(self, u, tmpdir, frames): u.atoms.write(destination, frames=selection) u_new = mda.Universe(destination, to_guess=()) - new_positions = np.stack( - [ts.positions.copy() for ts in u_new.trajectory] - ) + new_positions = np.stack([ts.positions.copy() for ts in u_new.trajectory]) assert_array_almost_equal(new_positions, ref_positions) @@ -181,9 +175,7 @@ def test_write_frames_all(self, u, tmpdir, compression): u_new = mda.Universe(destination, to_guess=()) ref_positions = np.stack([ts.positions.copy() for ts in u.trajectory]) - new_positions = np.stack( - [ts.positions.copy() for ts in u_new.trajectory] - ) + new_positions = np.stack([ts.positions.copy() for ts in u_new.trajectory]) assert_array_almost_equal(new_positions, ref_positions) @pytest.mark.parametrize("frames", ("invalid", 8, True, False, 3.2)) @@ -280,9 +272,7 @@ def test_write_selection(self, universe, outfile, selection): def test_write_Residue(self, universe, outfile): G = ( - universe.select_atoms("segid 4AKE and resname ARG") - .residues[-2] - .atoms + universe.select_atoms("segid 4AKE and resname ARG").residues[-2].atoms ) # 2nd to last Arg G.write(outfile) u2 = self.universe_from_tmp(outfile) @@ -295,8 +285,7 @@ def test_write_Residue(self, universe, outfile): G2.positions, G.positions, self.precision, - err_msg="written Residue R206 coordinates do not " - "agree with original", + err_msg="written Residue R206 coordinates do not " "agree with original", ) def test_write_Universe(self, universe, outfile): @@ -305,16 +294,13 @@ def test_write_Universe(self, universe, outfile): W.write(U) u2 = self.universe_from_tmp(outfile) assert len(u2.atoms) == len(U.atoms), ( - "written 4AKE universe does " - "not match original universe " - "in size" + "written 4AKE universe does " "not match original universe " "in size" ) assert_almost_equal( u2.atoms.positions, U.atoms.positions, self.precision, - err_msg="written universe 4AKE coordinates do not " - "agree with original", + err_msg="written universe 4AKE coordinates do not " "agree with original", ) @@ -376,9 +362,7 @@ def test_rotate(self, u, coords): ag.positions = vec.copy() res_ag = ag.rotate(R[:3, :3]) assert_equal(ag, res_ag) - assert_almost_equal( - ag.positions[0], [np.cos(angle), np.sin(angle), 0] - ) + assert_almost_equal(ag.positions[0], [np.cos(angle), np.sin(angle), 0]) ag.positions = vec.copy() ag.rotate(R[:3, :3], vec[0]) @@ -405,9 +389,7 @@ def test_rotateby(self, u, coords): # needs to be rotated about origin res_ag = ag.rotateby(np.rad2deg(angle), axis) assert_equal(res_ag, ag) - assert_almost_equal( - ag.positions[0], [np.cos(angle), np.sin(angle), 0] - ) + assert_almost_equal(ag.positions[0], [np.cos(angle), np.sin(angle), 0]) ag.positions = vec.copy() ag.rotateby(np.rad2deg(angle), axis, point=vec[0]) @@ -432,9 +414,7 @@ def test_transform_rotation_only(self, u, coords): R = transformations.rotation_matrix(angle, axis) ag.positions = vec.copy() ag.transform(R) - assert_almost_equal( - ag.positions[0], [np.cos(angle), np.sin(angle), 0] - ) + assert_almost_equal(ag.positions[0], [np.cos(angle), np.sin(angle), 0]) def test_transform_translation_only(self, u, center_of_geometry): disp = np.ones(3) @@ -457,9 +437,7 @@ def test_transform_translation_and_rotation(self, u): ag.positions = [[1, 0, 0], [-1, 0, 0]] ag.transform(T) - assert_almost_equal( - ag.positions[0], [np.cos(angle) + 1, np.sin(angle) + 1, 1] - ) + assert_almost_equal(ag.positions[0], [np.cos(angle) + 1, np.sin(angle) + 1, 1]) class TestCenter(object): @@ -520,9 +498,7 @@ def test_center_unwrap(self, level, compound, is_triclinic): group = group.segments # get the expected results - center = group.center( - weights=None, wrap=False, compound=compound, unwrap=True - ) + center = group.center(weights=None, wrap=False, compound=compound, unwrap=True) ref_center = u.center(compound=compound) assert_almost_equal(ref_center, center, decimal=4) @@ -532,9 +508,7 @@ def test_center_unwrap_wrap_true_group(self): # select group appropriate for compound: group = u.atoms[39:47] # molecule 12 with pytest.raises(ValueError): - group.center( - weights=None, compound="group", unwrap=True, wrap=True - ) + group.center(weights=None, compound="group", unwrap=True, wrap=True) class TestSplit(object): @@ -542,9 +516,7 @@ class TestSplit(object): @pytest.fixture() def ag(self): universe = mda.Universe(PSF, DCD) - return universe.select_atoms( - "resid 1:50 and not resname LYS and " "name CA CB" - ) + return universe.select_atoms("resid 1:50 and not resname LYS and " "name CA CB") def test_split_atoms(self, ag): sg = ag.split("atom") @@ -641,8 +613,7 @@ def test_ag_matches_atom(self, att, atts, ag, att_type): assert_equal( ref, getattr(ag, atts), - err_msg="AtomGroup doesn't match Atoms for property: " - "{0}".format(att), + err_msg="AtomGroup doesn't match Atoms for property: " "{0}".format(att), ) @pytest.mark.parametrize("att, atts, att_type", attributes) @@ -1226,9 +1197,7 @@ def test_residues(self, ag, unwrap, ref, method_name): result = method(compound="residues") assert_almost_equal(result, ref[method_name], self.prec) - @pytest.mark.parametrize( - "unwrap, ref", ((True, ref_Unwrap), (False, ref_noUnwrap)) - ) + @pytest.mark.parametrize("unwrap, ref", ((True, ref_Unwrap), (False, ref_noUnwrap))) @pytest.mark.parametrize( "method_name", ( @@ -1327,9 +1296,7 @@ def ag(self): universe = mda.Universe(TRZ_psf, TRZ) return universe.residues[0:3] - @pytest.mark.parametrize( - "wrap, ref", ((True, ref_PBC), (False, ref_noPBC)) - ) + @pytest.mark.parametrize("wrap, ref", ((True, ref_PBC), (False, ref_noPBC))) @pytest.mark.parametrize( "method_name", ( @@ -1463,9 +1430,7 @@ def test_center_of_mass(self, ag): decimal=5, ) - @pytest.mark.parametrize( - "method_name", ("center_of_geometry", "center_of_mass") - ) + @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) def test_center_duplicates(self, ag, method_name): ag2 = ag + ag[0] ref = getattr(ag, method_name)() @@ -1473,9 +1438,7 @@ def test_center_duplicates(self, ag, method_name): assert not np.allclose(getattr(ag2, method_name)(), ref) assert len(w) == 1 - @pytest.mark.parametrize( - "method_name", ("center_of_geometry", "center_of_mass") - ) + @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) @pytest.mark.parametrize( "name, compound", (("resids", "residues"), ("segids", "segments")) ) @@ -1484,43 +1447,30 @@ def test_center_compounds(self, ag, name, compound, method_name): vals = getattr(ag, method_name)(wrap=False, compound=compound) assert_almost_equal(vals, ref, decimal=5) - @pytest.mark.parametrize( - "method_name", ("center_of_geometry", "center_of_mass") - ) + @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) @pytest.mark.parametrize( "name, compound", (("resids", "residues"), ("segids", "segments")) ) @pytest.mark.parametrize("unwrap", (True, False)) - def test_center_compounds_pbc( - self, ag, name, compound, unwrap, method_name - ): + def test_center_compounds_pbc(self, ag, name, compound, unwrap, method_name): ag.dimensions = [50, 50, 50, 90, 90, 90] ref = [ - getattr(a, method_name)(unwrap=unwrap) - for a in ag.groupby(name).values() + getattr(a, method_name)(unwrap=unwrap) for a in ag.groupby(name).values() ] vals = getattr(ag, method_name)(compound=compound, unwrap=unwrap) assert_almost_equal(vals, ref, decimal=5) - @pytest.mark.parametrize( - "method_name", ("center_of_geometry", "center_of_mass") - ) + @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) @pytest.mark.parametrize( "name, compound", (("molnums", "molecules"), ("fragindices", "fragments")), ) - def test_center_compounds_special( - self, ag_molfrg, name, compound, method_name - ): - ref = [ - getattr(a, method_name)() for a in ag_molfrg.groupby(name).values() - ] + def test_center_compounds_special(self, ag_molfrg, name, compound, method_name): + ref = [getattr(a, method_name)() for a in ag_molfrg.groupby(name).values()] vals = getattr(ag_molfrg, method_name)(wrap=False, compound=compound) assert_almost_equal(vals, ref, decimal=5) - @pytest.mark.parametrize( - "method_name", ("center_of_geometry", "center_of_mass") - ) + @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) @pytest.mark.parametrize( "name, compound", (("molnums", "molecules"), ("fragindices", "fragments")), @@ -1534,9 +1484,7 @@ def test_center_compounds_special_pbc( getattr(a, method_name)(unwrap=unwrap) for a in ag_molfrg.groupby(name).values() ] - vals = getattr(ag_molfrg, method_name)( - compound=compound, unwrap=unwrap - ) + vals = getattr(ag_molfrg, method_name)(compound=compound, unwrap=unwrap) assert_almost_equal(vals, ref, decimal=5) def test_center_wrong_compound(self, ag): @@ -1548,9 +1496,7 @@ def test_center_compounds_special_fail(self, ag_no_molfrg, compound): with pytest.raises(NoDataError): ag_no_molfrg.center(weights=None, compound=compound) - @pytest.mark.parametrize( - "weights", (None, np.array([0.0]), np.array([2.0])) - ) + @pytest.mark.parametrize("weights", (None, np.array([0.0]), np.array([2.0]))) @pytest.mark.parametrize( "compound", ("group", "residues", "segments", "molecules", "fragments") ) @@ -1591,18 +1537,14 @@ def test_center_compounds_empty(self, ag_molfrg, wrap, weights, compound): ("fragindices", "fragments"), ), ) - def test_center_compounds_zero_weights( - self, ag_molfrg, wrap, name, compound - ): + def test_center_compounds_zero_weights(self, ag_molfrg, wrap, name, compound): if compound == "group": ref = np.full((3,), np.nan) else: n_compounds = len(ag_molfrg.groupby(name)) ref = np.full((n_compounds, 3), np.nan, dtype=np.float64) weights = np.zeros(len(ag_molfrg)) - assert_equal( - ref, ag_molfrg.center(weights, wrap=wrap, compound=compound) - ) + assert_equal(ref, ag_molfrg.center(weights, wrap=wrap, compound=compound)) def test_coordinates(self, ag): assert_almost_equal( @@ -1785,17 +1727,14 @@ def test_packintobox(self, universe): # Check with duplicates: ag += ag ag.pack_into_box(box=box) - assert_almost_equal( - ag.positions, np.vstack((packed_coords, packed_coords)) - ) + assert_almost_equal(ag.positions, np.vstack((packed_coords, packed_coords))) def test_residues(self, universe): u = universe assert_equal( u.residues[100].atoms.ix, u.select_atoms("resname ILE and resid 101").atoms.ix, - "Direct selection from residue group does not match " - "expected I101.", + "Direct selection from residue group does not match " "expected I101.", ) def test_index_integer(self, universe): @@ -2073,9 +2012,7 @@ def test_sort(self, ag, inputs, expected): assert np.array_equal(expected, agsort.ix) def test_sort_bonds(self, ag): - with pytest.raises( - ValueError, match=r"The array returned by the " "attribute" - ): + with pytest.raises(ValueError, match=r"The array returned by the " "attribute"): ag.sort("bonds") def test_sort_positions_2D(self, ag): diff --git a/testsuite/MDAnalysisTests/core/test_atomselections.py b/testsuite/MDAnalysisTests/core/test_atomselections.py index f7d0c5fc10..e69e220a6b 100644 --- a/testsuite/MDAnalysisTests/core/test_atomselections.py +++ b/testsuite/MDAnalysisTests/core/test_atomselections.py @@ -119,9 +119,7 @@ def test_resid_single(self, universe): def test_resid_range(self, universe): sel = universe.select_atoms("resid 100:105") assert_equal(sel.n_atoms, 89) - assert_equal( - sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"] - ) + assert_equal(sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"]) def test_selgroup(self, universe): sel = universe.select_atoms("not resid 100") @@ -148,23 +146,15 @@ def test_resnum_range(self, universe): sel = universe.select_atoms("resnum 100:105") assert_equal(sel.n_atoms, 89) assert_equal(sel.residues.resids, range(100, 106)) - assert_equal( - sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"] - ) + assert_equal(sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"]) def test_resname(self, universe): sel = universe.select_atoms("resname LEU") - assert_equal( - sel.n_atoms, 304, "Failed to find all 'resname LEU' atoms." - ) - assert_equal( - sel.n_residues, 16, "Failed to find all 'resname LEU' residues." - ) + assert_equal(sel.n_atoms, 304, "Failed to find all 'resname LEU' atoms.") + assert_equal(sel.n_residues, 16, "Failed to find all 'resname LEU' residues.") assert_equal( sorted(sel.indices), - sorted( - universe.select_atoms("segid 4AKE and resname LEU").indices - ), + sorted(universe.select_atoms("segid 4AKE and resname LEU").indices), "selected 'resname LEU' atoms are not the same as auto-generated s4AKE.LEU", ) @@ -178,9 +168,7 @@ def test_atom(self, universe): assert_equal(sel.resnames, ["GLY"]) assert_equal( sel.positions, - np.array( - [[20.38685226, -3.44224262, -5.92158318]], dtype=np.float32 - ), + np.array([[20.38685226, -3.44224262, -5.92158318]], dtype=np.float32), ) def test_atom_empty(self, universe): @@ -322,10 +310,7 @@ def test_same_resname(self, universe): assert_equal( len(sel), 331, - ( - "Found a wrong number of atoms with same resname as " - "resids 10 or 11" - ), + ("Found a wrong number of atoms with same resname as " "resids 10 or 11"), ) # fmt: off target_resids = np.array( @@ -420,9 +405,7 @@ def test_no_space_around_parentheses(self, universe): def test_concatenated_selection(self, universe): E151 = universe.select_atoms("segid 4AKE").select_atoms("resid 151") # note that this is not quite phi... HN should be C of prec. residue - phi151 = E151.atoms.select_atoms( - "name HN", "name N", "name CA", "name CB" - ) + phi151 = E151.atoms.select_atoms("name HN", "name N", "name CA", "name CB") assert_equal(len(phi151), 4) assert_equal( phi151[0].name, @@ -434,9 +417,7 @@ def test_global(self, universe): """Test the `global` modifier keyword (Issue 268)""" ag = universe.select_atoms("resname LYS and name NZ") # Lys amines within 4 angstrom of the backbone. - ag1 = universe.select_atoms( - "resname LYS and name NZ and around 4 backbone" - ) + ag1 = universe.select_atoms("resname LYS and name NZ and around 4 backbone") ag2 = ag.select_atoms("around 4 global backbone") assert_equal(ag2.indices, ag1.indices) @@ -487,12 +468,8 @@ def universe(self): def test_protein(self, universe): # must include non-standard residues sel = universe.select_atoms("protein or resname HAO or resname ORT") - assert_equal( - sel.n_atoms, universe.atoms.n_atoms, "failed to select peptide" - ) - assert_equal( - sel.n_residues, 6, "failed to select all peptide residues" - ) + assert_equal(sel.n_atoms, universe.atoms.n_atoms, "failed to select peptide") + assert_equal(sel.n_residues, 6, "failed to select all peptide residues") def test_resid_single(self, universe): sel = universe.select_atoms("resid 12") @@ -582,9 +559,7 @@ def test_same_fragment(self, universe, selstr): # This test comes here because it's a system with solvent, # and thus multiple fragments. sel = universe.select_atoms(selstr) - errmsg = ( - "Found a wrong number of atoms " "on the same fragment as id 1" - ) + errmsg = "Found a wrong number of atoms " "on the same fragment as id 1" assert_equal(len(sel), 3341, errmsg) errmsg = ( "Found a differ set of atoms when using the 'same " @@ -687,9 +662,7 @@ def test_passing_rdkit_kwargs_to_converter(self): def test_passing_max_matches_to_converter(self, u2): with pytest.warns(UserWarning, match="Your smarts-based") as wsmg: sel = u2.select_atoms("smarts C", smarts_kwargs=dict(maxMatches=2)) - sel2 = u2.select_atoms( - "smarts C", smarts_kwargs=dict(maxMatches=1000) - ) + sel2 = u2.select_atoms("smarts C", smarts_kwargs=dict(maxMatches=1000)) assert sel.n_atoms == 2 assert sel2.n_atoms == 3 @@ -900,9 +873,7 @@ class TestOrthogonalDistanceSelections(BaseDistanceSelection): def u(self): return mda.Universe(TRZ_psf, TRZ) - @pytest.mark.parametrize( - "meth, periodic", [("distmat", True), ("distmat", False)] - ) + @pytest.mark.parametrize("meth, periodic", [("distmat", True), ("distmat", False)]) def test_cyzone(self, u, meth, periodic): sel = Parser.parse("cyzone 5 4 -4 resid 2", u.atoms) sel.periodic = periodic @@ -1170,9 +1141,7 @@ def test_flip(self, prop, ag, op): # reference group, doing things forwards ref = ag[func(getattr(ag, self.plurals[prop]), 1.5)] - selstr = "prop 1.5 {op} {prop}".format( - op=self.opposites[op], prop=prop - ) + selstr = "prop 1.5 {op} {prop}".format(op=self.opposites[op], prop=prop) sel = ag.select_atoms(selstr) assert_equal(set(ref.indices), set(sel.indices)) @@ -1203,9 +1172,7 @@ class TestSelectionErrors(object): @staticmethod @pytest.fixture() def universe(): - return make_Universe( - ("names", "masses", "resids", "resnames", "resnums") - ) + return make_Universe(("names", "masses", "resids", "resnames", "resnums")) @pytest.mark.parametrize( "selstr", @@ -1307,9 +1274,7 @@ def test_string_selections(self, ref, sel, universe): ], ) def test_range_selections(self, seltype, ref, sel, universe): - self._check_sels( - ref.format(typ=seltype), sel.format(typ=seltype), universe - ) + self._check_sels(ref.format(typ=seltype), sel.format(typ=seltype), universe) class TestICodeSelection(object): @@ -1652,9 +1617,7 @@ def test_bool_sel_error(): def test_error_selection_for_strange_dtype(): with pytest.raises(ValueError, match="No base class defined for dtype"): - MDAnalysis.core.selection.gen_selection_class( - "star", "stars", dict, "atom" - ) + MDAnalysis.core.selection.gen_selection_class("star", "stars", dict, "atom") @pytest.mark.parametrize( @@ -1721,9 +1684,7 @@ def test_chirality(smi, chirality): assert u.atoms[0].chirality == "" assert u.atoms[1].chirality == chirality - assert_equal( - u.atoms[:3].chiralities, np.array(["", chirality, ""], dtype="U1") - ) + assert_equal(u.atoms[:3].chiralities, np.array(["", chirality, ""], dtype="U1")) @pytest.mark.parametrize( diff --git a/testsuite/MDAnalysisTests/core/test_group_traj_access.py b/testsuite/MDAnalysisTests/core/test_group_traj_access.py index f7061177f4..0939f52b56 100644 --- a/testsuite/MDAnalysisTests/core/test_group_traj_access.py +++ b/testsuite/MDAnalysisTests/core/test_group_traj_access.py @@ -125,9 +125,7 @@ def test_atomgroup_velocities_access(self, u, vel): else: with pytest.raises(NoDataError): getattr(ag, "velocities") - assert_correct_errormessage( - (getattr, ag, "velocities"), "velocities" - ) + assert_correct_errormessage((getattr, ag, "velocities"), "velocities") def test_atomgroup_forces_access(self, u, force): ag = u.atoms[10:20] @@ -167,9 +165,7 @@ def test_atom_velocity_access(self, u, vel): else: with pytest.raises(NoDataError): getattr(at, "velocity") - assert_correct_errormessage( - (getattr, at, "velocity"), "velocities" - ) + assert_correct_errormessage((getattr, at, "velocity"), "velocities") def test_atom_force_access(self, u, force): at = u.atoms[55] @@ -189,25 +185,18 @@ def test_atom_force_access(self, u, force): def test_atomgroup_positions_setting(self, u): ag = u.atoms[[101, 107, 109]] - new = np.array( - [[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]] - ) + new = np.array([[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]]) ag.positions = new assert_almost_equal(ag.positions, new, decimal=5) - assert_almost_equal( - u.trajectory.ts.positions[[101, 107, 109]], new, decimal=5 - ) + assert_almost_equal(u.trajectory.ts.positions[[101, 107, 109]], new, decimal=5) def test_atomgroup_velocities_setting(self, u, vel): ag = u.atoms[[101, 107, 109]] new = ( - np.array( - [[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]] - ) - + 0.1 + np.array([[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]]) + 0.1 ) if vel: @@ -220,27 +209,20 @@ def test_atomgroup_velocities_setting(self, u, vel): else: with pytest.raises(NoDataError): setattr(ag, "velocities", new) - assert_correct_errormessage( - (setattr, ag, "velocities", new), "velocities" - ) + assert_correct_errormessage((setattr, ag, "velocities", new), "velocities") def test_atomgroup_forces_setting(self, u, force): ag = u.atoms[[101, 107, 109]] new = ( - np.array( - [[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]] - ) - + 0.2 + np.array([[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]]) + 0.2 ) if force: ag.forces = new assert_almost_equal(ag.forces, new, decimal=5) - assert_almost_equal( - u.trajectory.ts.forces[[101, 107, 109]], new, decimal=5 - ) + assert_almost_equal(u.trajectory.ts.forces[[101, 107, 109]], new, decimal=5) else: with pytest.raises(NoDataError): setattr(ag, "forces", new) @@ -269,9 +251,7 @@ def test_atom_velocity_setting(self, u, vel): else: with pytest.raises(NoDataError): setattr(at, "velocity", new) - assert_correct_errormessage( - (setattr, at, "velocity", new), "velocities" - ) + assert_correct_errormessage((setattr, at, "velocity", new), "velocities") def test_atom_force_setting(self, u, force): at = u.atoms[94] @@ -479,9 +459,7 @@ def test_velocities(self, universe): ] ) v = ag.velocities - assert_almost_equal( - v, ref_v, err_msg="velocities were not read correctly" - ) + assert_almost_equal(v, ref_v, err_msg="velocities were not read correctly") def test_set_velocities(self, ag): ag = ag @@ -516,6 +494,4 @@ def test_forces(self, universe): def test_set_forces(self, ag): v = ag.forces - 2.7271 ag.forces = v - assert_almost_equal( - ag.forces, v, err_msg="messages were not set to new value" - ) + assert_almost_equal(ag.forces, v, err_msg="messages were not set to new value") diff --git a/testsuite/MDAnalysisTests/core/test_groups.py b/testsuite/MDAnalysisTests/core/test_groups.py index 7cd890b046..ef8c8c85e8 100644 --- a/testsuite/MDAnalysisTests/core/test_groups.py +++ b/testsuite/MDAnalysisTests/core/test_groups.py @@ -142,9 +142,7 @@ def test_create_unique_group_from_unique(self, group): # check if caches of group.sorted_unique have been set correctly: assert group.sorted_unique._cache["isunique"] is True - assert ( - group.sorted_unique._cache["sorted_unique"] is group.sorted_unique - ) + assert group.sorted_unique._cache["sorted_unique"] is group.sorted_unique # assert that repeated access yields the same object (not a copy): unique_group = group.sorted_unique assert unique_group is group.sorted_unique @@ -509,9 +507,7 @@ def test_sum(self, a, b, c, refclass): assert_equal( len(summed), len(self.itr(a)) + len(self.itr(b)) + len(self.itr(c)) ) - for x, y in zip( - summed, itertools.chain(self.itr(a), self.itr(b), self.itr(c)) - ): + for x, y in zip(summed, itertools.chain(self.itr(a), self.itr(b), self.itr(c))): assert x == y @pytest.mark.parametrize( @@ -531,11 +527,7 @@ def test_contains_false(self, group): @pytest.mark.parametrize( "one_level, other_level", - [ - (l1, l2) - for l1, l2 in itertools.product(levels, repeat=2) - if l1 != l2 - ], + [(l1, l2) for l1, l2 in itertools.product(levels, repeat=2) if l1 != l2], ) def test_contains_wronglevel(self, one_level, other_level): group = self.group_dict[one_level] @@ -993,8 +985,7 @@ def u(self): def test_atom_repr(self, u): at = u.atoms[0] assert ( - repr(at) - == "" + repr(at) == "" ) def test_residue_repr(self, u): @@ -1018,9 +1009,7 @@ def test_atomgroup_str_short(self, u): def test_atomgroup_str_long(self, u): ag = u.atoms[:11] - assert str(ag).startswith( - "]>") @@ -1122,9 +1111,7 @@ def test_len(self, groups_simple): assert_equal(len(d), 0) assert_equal(len(e), 3) - def test_len_duplicated_and_scrambled( - self, groups_duplicated_and_scrambled - ): + def test_len_duplicated_and_scrambled(self, groups_duplicated_and_scrambled): a, b, c, d, e = groups_duplicated_and_scrambled assert_equal(len(a), 7) assert_equal(len(b), 8) @@ -1137,13 +1124,9 @@ def test_equal(self, groups): assert a == a assert a != b assert not a == b - assert ( - not a[0:1] == a[0] - ), "Element should not equal single element group." + assert not a[0:1] == a[0], "Element should not equal single element group." - @pytest.mark.parametrize( - "group", (u.atoms[:2], u.residues[:2], u.segments[:2]) - ) + @pytest.mark.parametrize("group", (u.atoms[:2], u.residues[:2], u.segments[:2])) def test_copy(self, group): # make sure uniqueness caches of group are empty: with pytest.raises(KeyError): @@ -1399,9 +1382,7 @@ def test_hash_difference(self, u, level): b = getattr(u, level)[1:] assert hash(a) != hash(b) - @pytest.mark.parametrize( - "level_a, level_b", itertools.permutations(levels, 2) - ) + @pytest.mark.parametrize("level_a, level_b", itertools.permutations(levels, 2)) def test_hash_difference_cross(self, u, level_a, level_b): a = getattr(u, level_a)[0:-1] b = getattr(u, level_b)[0:-1] @@ -1579,9 +1560,7 @@ def test_unwrap_without_bonds(self, universe): def test_get_absent_attr_method(self, universe): with pytest.raises(NoDataError) as exc: universe.atoms.total_charge() - err = ( - "AtomGroup.total_charge() not available; " "this requires charges" - ) + err = "AtomGroup.total_charge() not available; " "this requires charges" assert str(exc.value) == err def test_get_absent_attrprop(self, universe): @@ -1606,9 +1585,7 @@ def test_attrmethod_wrong_group(self, universe): def test_wrong_name(self, universe, attr): with pytest.raises(AttributeError) as exc: getattr(universe.atoms, attr) - err = ( - "AtomGroup has no attribute {}. " "Did you mean altLocs?" - ).format(attr) + err = ("AtomGroup has no attribute {}. " "Did you mean altLocs?").format(attr) assert str(exc.value) == err @@ -1685,9 +1662,7 @@ def test_wrap_and_unwrap_deprecation(self, compound, pbc, unwrap): # deprecation. We need to tell the linter. assert ( # pylint: disable-next=unexpected-keyword-arg - self.dummy_funtion( - compound=compound, pbc=pbc, unwrap=unwrap - ) + self.dummy_funtion(compound=compound, pbc=pbc, unwrap=unwrap) == 0 ) @@ -1702,10 +1677,7 @@ def test_wrap_and_unwrap(self, compound, wrap, unwrap): with pytest.raises(ValueError): self.dummy_funtion(compound=compound, wrap=wrap, unwrap=unwrap) else: - assert ( - self.dummy_funtion(compound=compound, wrap=wrap, unwrap=unwrap) - == 0 - ) + assert self.dummy_funtion(compound=compound, wrap=wrap, unwrap=unwrap) == 0 @pytest.fixture() @@ -1718,9 +1690,7 @@ def tpr(): class TestGetConnectionsAtoms(object): """Test Atom and AtomGroup.get_connections""" - @pytest.mark.parametrize( - "typename", ["bonds", "angles", "dihedrals", "impropers"] - ) + @pytest.mark.parametrize("typename", ["bonds", "angles", "dihedrals", "impropers"]) def test_connection_from_atom_not_outside(self, tpr, typename): cxns = tpr.atoms[1].get_connections(typename, outside=False) assert len(cxns) == 0 @@ -1818,9 +1788,7 @@ def test_connection_from_res_outside(self, tpr, typename, n_atoms): ("dihedrals", 351), ], ) - def test_connection_from_residues_not_outside( - self, tpr, typename, n_atoms - ): + def test_connection_from_residues_not_outside(self, tpr, typename, n_atoms): ag = tpr.residues[:10] cxns = ag.get_connections(typename, outside=False) assert len(cxns) == n_atoms diff --git a/testsuite/MDAnalysisTests/core/test_residuegroup.py b/testsuite/MDAnalysisTests/core/test_residuegroup.py index 06d0e22e9a..4a2efc9469 100644 --- a/testsuite/MDAnalysisTests/core/test_residuegroup.py +++ b/testsuite/MDAnalysisTests/core/test_residuegroup.py @@ -56,9 +56,7 @@ def u(self): def test_string(self, u): p = u.select_atoms("protein") - assert_equal( - p.residues.sequence(format="string"), self.ref_adk_sequence - ) + assert_equal(p.residues.sequence(format="string"), self.ref_adk_sequence) def test_SeqRecord(self, u): p = u.select_atoms("protein") @@ -190,8 +188,7 @@ def test_set_resids_updates_self(self, universe): assert_equal( rg.resids, resids, - err_msg="old selection was not changed in place " - "after set_resid", + err_msg="old selection was not changed in place " "after set_resid", ) def test_set_resnum_single(self, universe): @@ -297,9 +294,7 @@ def test_set_masses(self, universe): assert_equal( [a.mass for a in rg.atoms], mass * np.ones(rg.n_atoms), - err_msg="failed to set_mass H* atoms in resid 12:42 to {0}".format( - mass - ), + err_msg="failed to set_mass H* atoms in resid 12:42 to {0}".format(mass), ) # VALID diff --git a/testsuite/MDAnalysisTests/core/test_topology.py b/testsuite/MDAnalysisTests/core/test_topology.py index d1154f5c4e..b34666f774 100644 --- a/testsuite/MDAnalysisTests/core/test_topology.py +++ b/testsuite/MDAnalysisTests/core/test_topology.py @@ -722,9 +722,7 @@ def names(self): @pytest.fixture() def types(self): - return ta.Atomtypes( - np.array(["X", "Y", "Z"], dtype=object), guessed=True - ) + return ta.Atomtypes(np.array(["X", "Y", "Z"], dtype=object), guessed=True) @pytest.fixture() def resids(self): diff --git a/testsuite/MDAnalysisTests/core/test_topologyattrs.py b/testsuite/MDAnalysisTests/core/test_topologyattrs.py index 5155933c2e..4be0bcb764 100644 --- a/testsuite/MDAnalysisTests/core/test_topologyattrs.py +++ b/testsuite/MDAnalysisTests/core/test_topologyattrs.py @@ -233,9 +233,7 @@ class AggregationMixin(TestAtomAttr): def test_get_residues(self, attr): assert_equal( attr.get_residues(DummyGroup([2, 1])), - np.array( - [self.values[[2, 3, 9]].sum(), self.values[[4, 5, 8]].sum()] - ), + np.array([self.values[[2, 3, 9]].sum(), self.values[[4, 5, 8]].sum()]), ) def test_get_segments(self, attr): @@ -281,9 +279,7 @@ def test_set_residue_VE(self, universe): setattr(res, self.attrclass.singular, self.values[:2]) def test_get_atoms(self, attr): - assert_equal( - attr.get_atoms(DummyGroup([7, 3, 9])), self.values[[3, 2, 2]] - ) + assert_equal(attr.get_atoms(DummyGroup([7, 3, 9])), self.values[[3, 2, 2]]) def test_get_atom(self, universe): attr = getattr(universe.atoms[0], self.attrclass.singular) @@ -375,9 +371,7 @@ def test_set_segment_VE(self): setattr(seg, "segid", [1, 2, 3]) def test_get_atoms(self, attr): - assert_equal( - attr.get_atoms(DummyGroup([2, 4, 1])), self.values[[1, 1, 0]] - ) + assert_equal(attr.get_atoms(DummyGroup([2, 4, 1])), self.values[[1, 1, 0]]) def test_get_residues(self, attr): assert_equal( @@ -390,9 +384,7 @@ def test_get_segments(self, attr): atoms in segments. """ - assert_equal( - attr.get_segments(DummyGroup([1, 0, 0])), self.values[[1, 0, 0]] - ) + assert_equal(attr.get_segments(DummyGroup([1, 0, 0])), self.values[[1, 0, 0]]) def test_set_segments_singular(self, attr): dg = DummyGroup([0, 1]) @@ -434,9 +426,7 @@ def universe_pa(self): def test_principal_axes_handedness(self, universe_pa): e_vec = universe_pa.atoms.principal_axes() - assert_almost_equal( - np.dot(np.cross(e_vec[0], e_vec[1]), e_vec[2]), 1.0 - ) + assert_almost_equal(np.dot(np.cross(e_vec[0], e_vec[1]), e_vec[2]), 1.0) def test_align_principal_axes_with_self(self, ag): pa = ag.principal_axes() diff --git a/testsuite/MDAnalysisTests/core/test_topologyobjects.py b/testsuite/MDAnalysisTests/core/test_topologyobjects.py index 196b91364d..7c54eeb16e 100644 --- a/testsuite/MDAnalysisTests/core/test_topologyobjects.py +++ b/testsuite/MDAnalysisTests/core/test_topologyobjects.py @@ -221,9 +221,7 @@ def test_ureybradley_partner(self, PSFDCD): assert ub.partner(PSFDCD.atoms[10]) == PSFDCD.atoms[30] def test_ureybradley_distance(self, b): - assert_almost_equal( - b.atoms.ureybradley.distance(), b.length(), self.precision - ) + assert_almost_equal(b.atoms.ureybradley.distance(), b.length(), self.precision) def test_cmap_repr(self, PSFDCD): cmap = PSFDCD.atoms[[4, 7, 8, 1, 2]].cmap @@ -299,9 +297,7 @@ def test_bond_uniqueness(self, PSFDCD): bondtypes = PSFDCD.atoms.bonds.types() # check that a key doesn't appear in reversed format in keylist # have to exclude case of b[::-1] == b as this is false positive - assert not any( - [b[::-1] in bondtypes for b in bondtypes if b[::-1] != b] - ) + assert not any([b[::-1] in bondtypes for b in bondtypes if b[::-1] != b]) def test_bond_reversal(self, PSFDCD, b_td): bondtypes = PSFDCD.atoms.bonds.types() @@ -439,9 +435,7 @@ def test_create_TopologyGroup(self, res1, PSFDCD): res1_tg2 = res1.atoms.bonds.select_bonds(("23", "3")) assert res1_tg == res1_tg2 - @pytest.mark.parametrize( - "attr", ["bonds", "angles", "dihedrals", "impropers"] - ) + @pytest.mark.parametrize("attr", ["bonds", "angles", "dihedrals", "impropers"]) def test_TG_loose_intersection(self, PSFDCD, attr): """Pull bonds from a TG which are at least partially in an AG""" ag = PSFDCD.atoms[10:60] @@ -486,9 +480,7 @@ def manual(topg, atomg): # dihedrals assert check_strict_intersection(PSFDCD.atoms.dihedrals, testinput) assert manual(PSFDCD.atoms.dihedrals, testinput) == set( - PSFDCD.atoms.dihedrals.atomgroup_intersection( - testinput, strict=True - ) + PSFDCD.atoms.dihedrals.atomgroup_intersection(testinput, strict=True) ) def test_add_TopologyGroups(self, res1, res2, PSFDCD): diff --git a/testsuite/MDAnalysisTests/core/test_universe.py b/testsuite/MDAnalysisTests/core/test_universe.py index d931966b42..5299d3787f 100644 --- a/testsuite/MDAnalysisTests/core/test_universe.py +++ b/testsuite/MDAnalysisTests/core/test_universe.py @@ -100,9 +100,7 @@ def test_load(self): def test_load_topology_stringio(self): u = mda.Universe(StringIO(CHOL_GRO), format="GRO") - assert_equal( - len(u.atoms), 8, "Loading universe from StringIO failed somehow" - ) + assert_equal(len(u.atoms), 8, "Loading universe from StringIO failed somehow") assert_equal( u.trajectory.ts.positions[0], np.array([65.580002, 29.360001, 40.050003], dtype=np.float32), @@ -115,9 +113,7 @@ def test_load_trajectory_stringio(self): format="GRO", topology_format="GRO", ) - assert_equal( - len(u.atoms), 8, "Loading universe from StringIO failed somehow" - ) + assert_equal(len(u.atoms), 8, "Loading universe from StringIO failed somehow") def test_make_universe_stringio_no_format(self): # Loading from StringIO without format arg should raise TypeError @@ -177,9 +173,7 @@ def test_Universe_invalidfile_IE_msg(self, tmpdir): else: raise AssertionError - @pytest.mark.skipif( - get_userid() == 0, reason="cannot permisssionerror as root" - ) + @pytest.mark.skipif(get_userid() == 0, reason="cannot permisssionerror as root") def test_Universe_invalidpermissionfile_IE_msg(self, tmpdir): # check for file with invalid permissions (eg. no read access) with tmpdir.as_cwd(): @@ -189,9 +183,7 @@ def test_Universe_invalidpermissionfile_IE_msg(self, tmpdir): if os.name == "nt": subprocess.call( - "icacls {filename} /deny Users:RX".format( - filename=temp_file - ), + "icacls {filename} /deny Users:RX".format(filename=temp_file), shell=True, ) else: @@ -212,9 +204,7 @@ def test_load_new_memory_reader_success(self): prot = u.select_atoms("protein") u2 = mda.Merge(prot) assert ( - u2.load_new( - [prot.positions], format=mda.coordinates.memory.MemoryReader - ) + u2.load_new([prot.positions], format=mda.coordinates.memory.MemoryReader) is u2 ) @@ -223,9 +213,7 @@ def load(): u = mda.Universe(GRO) prot = u.select_atoms("protein") u2 = mda.Merge(prot) - u2.load_new( - [[prot.positions]], format=mda.coordinates.memory.MemoryReader - ) + u2.load_new([[prot.positions]], format=mda.coordinates.memory.MemoryReader) with pytest.raises(TypeError): load() @@ -311,9 +299,7 @@ def test_rdkit_kwargs(self): u1 = mda.Universe.from_smiles("C", rdkit_kwargs=dict(randomSeed=42)) u2 = mda.Universe.from_smiles("C", rdkit_kwargs=dict(randomSeed=51)) with pytest.raises(AssertionError) as e: - assert_equal( - u1.trajectory.coordinate_array, u2.trajectory.coordinate_array - ) + assert_equal(u1.trajectory.coordinate_array, u2.trajectory.coordinate_array) assert "Mismatched elements: 15 / 15 (100%)" in str(e.value) def test_coordinates(self): @@ -330,9 +316,7 @@ def test_coordinates(self): expected = [c.GetPositions() for c in mol.GetConformers()] # now the mda way - u = mda.Universe.from_smiles( - "C", numConfs=2, rdkit_kwargs=dict(randomSeed=42) - ) + u = mda.Universe.from_smiles("C", numConfs=2, rdkit_kwargs=dict(randomSeed=42)) assert u.trajectory.n_frames == 2 assert_allclose(u.trajectory.coordinate_array, expected, rtol=1e-7) @@ -645,9 +629,7 @@ def test_frame_interval_convention(self): array1 = universe1.trajectory.timeseries(step=10) universe2 = mda.Universe(PSF, DCD, in_memory=True, in_memory_step=10) array2 = universe2.trajectory.timeseries() - assert_equal( - array1, array2, err_msg="Unexpected differences between arrays." - ) + assert_equal(array1, array2, err_msg="Unexpected differences between arrays.") def test_slicing_with_start_stop(self): universe = MDAnalysis.Universe(PDB_small, DCD) @@ -752,17 +734,13 @@ class TestCustomReaders(object): def test_custom_reader(self): # check that reader passing works - u = mda.Universe( - TRZ_psf, TRZ, format=MDAnalysis.coordinates.TRZ.TRZReader - ) + u = mda.Universe(TRZ_psf, TRZ, format=MDAnalysis.coordinates.TRZ.TRZReader) assert_equal(len(u.atoms), 8184) def test_custom_reader_singleframe(self): T = MDAnalysis.topology.GROParser.GROParser R = MDAnalysis.coordinates.GRO.GROReader - u = mda.Universe( - two_water_gro, two_water_gro, topology_format=T, format=R - ) + u = mda.Universe(two_water_gro, two_water_gro, topology_format=T, format=R) assert_equal(len(u.atoms), 6) def test_custom_reader_singleframe_2(self): @@ -889,9 +867,7 @@ def test_add_connection_error(self, universe, attr, values): def test_add_attr_length_error(self, universe): with pytest.raises(ValueError): - universe.add_TopologyAttr( - "masses", np.array([1, 2, 3], dtype=np.float64) - ) + universe.add_TopologyAttr("masses", np.array([1, 2, 3], dtype=np.float64)) class TestDelTopologyAttr(object): @@ -1058,20 +1034,14 @@ def test_add_atomgroup_to_populated(self, universe, attr, values): self._check_valid_added_to_populated(universe, attr, values, ag) @pytest.mark.parametrize("attr,values", small_atom_indices) - def test_add_atomgroup_wrong_universe_error( - self, universe, empty, attr, values - ): + def test_add_atomgroup_wrong_universe_error(self, universe, empty, attr, values): ag = [empty.atoms[x] for x in values] self._check_invalid_addition(universe, attr, ag, "different Universes") @pytest.mark.parametrize("attr,values", large_atom_indices) def test_add_topologyobjects_to_populated(self, universe, attr, values): - topologyobjects = [ - getattr(universe.atoms[x], attr[:-1]) for x in values - ] - self._check_valid_added_to_populated( - universe, attr, values, topologyobjects - ) + topologyobjects = [getattr(universe.atoms[x], attr[:-1]) for x in values] + self._check_valid_added_to_populated(universe, attr, values, topologyobjects) @pytest.mark.parametrize("attr,values", small_atom_indices) def test_add_topologyobjects_wrong_universe_error( @@ -1085,9 +1055,7 @@ def test_add_topologygroups_to_populated(self, universe, attr, values): topologygroup = mda.core.topologyobjects.TopologyGroup( np.array(values), universe ) - self._check_valid_added_to_populated( - universe, attr, values, topologygroup - ) + self._check_valid_added_to_populated(universe, attr, values, topologygroup) @pytest.mark.parametrize("attr,values", small_atom_indices) def test_add_topologygroup_wrong_universe_error( @@ -1097,9 +1065,7 @@ def test_add_topologygroup_wrong_universe_error( self._check_invalid_addition(empty, attr, tg, "different Universes") @pytest.mark.parametrize("attr,values", small_atom_indices) - def test_add_topologygroup_different_universe( - self, universe, empty, attr, values - ): + def test_add_topologygroup_different_universe(self, universe, empty, attr, values): tg = mda.core.topologyobjects.TopologyGroup(np.array(values), universe) self._check_valid_added_to_empty(empty, attr, values, tg.to_indices()) @@ -1115,9 +1081,7 @@ def test_add_topologygroup_different_universe( def test_add_wrong_topologygroup_error(self, universe, attr, values): arr = np.array(values) tg = mda.core.topologyobjects.TopologyGroup(arr, universe) - self._check_invalid_addition( - universe, attr, tg, "iterable of tuples with" - ) + self._check_invalid_addition(universe, attr, tg, "iterable of tuples with") @pytest.mark.parametrize( "attr,values", @@ -1132,9 +1096,7 @@ def test_add_wrong_topologygroup_error(self, universe, attr, values): ), ) def test_add_nonexistent_indices_error(self, universe, attr, values): - self._check_invalid_addition( - universe, attr, values, "nonexistent atom indices" - ) + self._check_invalid_addition(universe, attr, values, "nonexistent atom indices") @pytest.mark.parametrize( "attr,n", @@ -1146,9 +1108,9 @@ def test_add_nonexistent_indices_error(self, universe, attr, values): ), ) def test_add_wrong_number_of_atoms_error(self, universe, attr, n): - errmsg = ( - "{} must be an iterable of " "tuples with {} atom indices" - ).format(attr, n) + errmsg = ("{} must be an iterable of " "tuples with {} atom indices").format( + attr, n + ) idx = [(0, 1), (0, 1, 2), (8, 22, 1, 3), (5, 3, 4, 2)] self._check_invalid_addition(universe, attr, idx, errmsg) @@ -1234,10 +1196,7 @@ def _check_valid_deleted(self, u, attr, values, to_delete): not_deleted = [x for x in self.TOP[attr] if list(x) not in values] assert all( - [ - x in u_attr.indices or x[::-1] in u_attr.indices - for x in not_deleted - ] + [x in u_attr.indices or x[::-1] in u_attr.indices for x in not_deleted] ) def _check_invalid_deleted(self, u, attr, to_delete, err_msg): @@ -1255,9 +1214,7 @@ def test_delete_valid_indices(self, universe, attr, values): @pytest.mark.parametrize("attr,values", nonexisting_atom_indices) def test_delete_missing_indices(self, universe, attr, values): - self._check_invalid_deleted( - universe, attr, values, "Cannot delete nonexistent" - ) + self._check_invalid_deleted(universe, attr, values, "Cannot delete nonexistent") @pytest.mark.parametrize("attr,values", existing_atom_indices) def test_delete_valid_atomgroup(self, universe, attr, values): @@ -1274,9 +1231,7 @@ def test_delete_atomgroup_wrong_universe_error( @pytest.mark.parametrize("attr,values", nonexisting_atom_indices) def test_delete_missing_atomgroup(self, universe, attr, values): ag = [universe.atoms[x] for x in values] - self._check_invalid_deleted( - universe, attr, ag, "Cannot delete nonexistent" - ) + self._check_invalid_deleted(universe, attr, ag, "Cannot delete nonexistent") @pytest.mark.parametrize("attr,values", existing_atom_indices) def test_delete_mixed_type(self, universe, attr, values): @@ -1294,9 +1249,7 @@ def test_delete_topologyobjects_wrong_universe( ): u1 = [getattr(universe.atoms[x], attr[:-1]) for x in values[:-1]] u2 = [getattr(universe2.atoms[values[-1]], attr[:-1])] - self._check_invalid_deleted( - universe, attr, u1 + u2, "different Universes" - ) + self._check_invalid_deleted(universe, attr, u1 + u2, "different Universes") @pytest.mark.parametrize("attr,values", existing_atom_indices) def test_delete_valid_topologygroup(self, universe, attr, values): @@ -1331,9 +1284,9 @@ def test_delete_topologygroup_different_universe( ) def test_delete_wrong_number_of_atoms_error(self, universe, attr, n): idx = [(0, 1), (0, 1, 2), (8, 22, 1, 3), (5, 3, 4, 2)] - errmsg = ( - "{} must be an iterable of " "tuples with {} atom indices" - ).format(attr, n) + errmsg = ("{} must be an iterable of " "tuples with {} atom indices").format( + attr, n + ) self._check_invalid_deleted(universe, attr, idx, errmsg) @pytest.mark.parametrize("attr,values", existing_atom_indices) @@ -1350,9 +1303,7 @@ def test_delete_bonds_refresh_fragments(self, universe): universe.delete_bonds([universe.atoms[[2, 3]]]) assert len(universe.atoms.fragments) == n_fragments + 1 - @pytest.mark.parametrize( - "filename, n_bonds", [(CONECT, 72), (PDB_conect, 8)] - ) + @pytest.mark.parametrize("filename, n_bonds", [(CONECT, 72), (PDB_conect, 8)]) def test_delete_all_bonds(self, filename, n_bonds): u = mda.Universe(filename) assert len(u.bonds) == n_bonds @@ -1393,16 +1344,12 @@ def u_GRO(self): def test_all_coordinates_length(self, u_GRO_TRR, u_GRO_TRR_allcoords): # length with all_coords should be +1 - assert len(u_GRO_TRR.trajectory) + 1 == len( - u_GRO_TRR_allcoords.trajectory - ) + assert len(u_GRO_TRR.trajectory) + 1 == len(u_GRO_TRR_allcoords.trajectory) def test_all_coordinates_frame(self, u_GRO_TRR_allcoords, u_GRO): # check that first frame in u(GRO, TRR, allcords) # are the coordinates from GRO - assert_array_equal( - u_GRO_TRR_allcoords.atoms.positions, u_GRO.atoms.positions - ) + assert_array_equal(u_GRO_TRR_allcoords.atoms.positions, u_GRO.atoms.positions) def test_second_frame(self, u_GRO_TRR_allcoords, u_GRO_TRR): # check that second frame in u(GRO, TRR, allcoords) @@ -1614,20 +1561,14 @@ def test_set_segments(self, bad_seg, good): assert_equal(["A", "", "A", "B", ""], bad_seg.segments.segids) assert len(bad_seg.residues) == 5 # 5 residues assert_equal([315, 315, 316, 314, 315], bad_seg.residues.resids) - assert_equal( - ["THR", "THR", "THR", "THR", "THR"], bad_seg.residues.resnames - ) + assert_equal(["THR", "THR", "THR", "THR", "THR"], bad_seg.residues.resnames) assert_equal(["A", "", "A", "B", ""], bad_seg.residues.segids) assert len(bad_seg.atoms) == 7 # 7 atoms assert_equal([315, 315, 315, 316, 314, 315, 315], bad_seg.atoms.resids) assert_equal(["THR"] * 7, bad_seg.atoms.resnames) assert_equal(["A", "", "", "A", "B", "", ""], bad_seg.atoms.segids) - assert_equal( - ["N", "CA", "C", "O", "CB", "CG2", "OG1"], bad_seg.atoms.names - ) - assert_equal( - ["A", "A", "A", "A", "B", "B", "B"], bad_seg.atoms.chainIDs - ) + assert_equal(["N", "CA", "C", "O", "CB", "CG2", "OG1"], bad_seg.atoms.names) + assert_equal(["A", "A", "A", "A", "B", "B", "B"], bad_seg.atoms.chainIDs) original_attrs = bad_seg._topology.attrs # [ACT] set new segids @@ -1774,9 +1715,7 @@ def test_with_ITP(self, itp): def test_with_TPR(self, tpr): # [BEFORE] assert len(tpr.segments) == 3 - assert_equal( - ["seg_0_AKeco", "seg_1_SOL", "seg_2_NA+"], tpr.segments.segids - ) + assert_equal(["seg_0_AKeco", "seg_1_SOL", "seg_2_NA+"], tpr.segments.segids) assert len(tpr.residues) == 11302 assert_equal(range(1, 11303, 1), tpr.residues.resids) orignial_res_molnums = tpr.residues.molnums diff --git a/testsuite/MDAnalysisTests/core/test_unwrap.py b/testsuite/MDAnalysisTests/core/test_unwrap.py index e6da223ee2..ecff4d68f9 100644 --- a/testsuite/MDAnalysisTests/core/test_unwrap.py +++ b/testsuite/MDAnalysisTests/core/test_unwrap.py @@ -70,17 +70,13 @@ def test_unwrap_pass(self, level, compound, reference, is_triclinic): if compound == "group": ref_unwrapped_pos = ref_unwrapped_pos[39:47] # molecule 12 elif compound == "segments": - ref_unwrapped_pos = ref_unwrapped_pos[ - 23:47 - ] # molecules 10, 11, 12 + ref_unwrapped_pos = ref_unwrapped_pos[23:47] # molecules 10, 11, 12 # first, do the unwrapping out-of-place: unwrapped_pos = group.unwrap( compound=compound, reference=reference, inplace=False ) # check for correct result: - assert_almost_equal( - unwrapped_pos, ref_unwrapped_pos, decimal=self.precision - ) + assert_almost_equal(unwrapped_pos, ref_unwrapped_pos, decimal=self.precision) # make sure atom positions are unchanged: assert_array_equal(group.atoms.positions, orig_pos) # now, do the unwrapping inplace: @@ -143,9 +139,7 @@ def test_unwrap_partial_frags(self, compound, reference, is_triclinic): # first, do the unwrapping out-of-place: group.unwrap(compound=compound, reference=reference, inplace=True) # check for correct result: - assert_almost_equal( - group.positions, ref_unwrapped_pos, decimal=self.precision - ) + assert_almost_equal(group.positions, ref_unwrapped_pos, decimal=self.precision) # make sure the position of molecule 12's last atom is unchanged: assert_array_equal(u.atoms[46].position, orig_pos) @@ -155,9 +149,7 @@ def test_unwrap_partial_frags(self, compound, reference, is_triclinic): ) @pytest.mark.parametrize("reference", ("com", "cog", None)) @pytest.mark.parametrize("is_triclinic", (False, True)) - def test_unwrap_empty_group( - self, level, compound, reference, is_triclinic - ): + def test_unwrap_empty_group(self, level, compound, reference, is_triclinic): # get a pristine test universe: u = UnWrapUniverse(is_triclinic=is_triclinic) if level == "atoms": @@ -168,9 +160,7 @@ def test_unwrap_empty_group( group = mda.SegmentGroup([], u) group.unwrap(compound=compound, reference=reference, inplace=True) # check for correct (empty) result: - assert_array_equal( - group.atoms.positions, np.empty((0, 3), dtype=np.float32) - ) + assert_array_equal(group.atoms.positions, np.empty((0, 3), dtype=np.float32)) @pytest.mark.parametrize("level", ("atoms", "residues", "segments")) @pytest.mark.parametrize( @@ -350,9 +340,7 @@ def test_unwrap_no_masses_exception_safety(self, level, compound): "compound", ("fragments", "molecules", "residues", "group", "segments") ) @pytest.mark.parametrize("reference", ("com", "cog", None)) - def test_unwrap_no_bonds_exception_safety( - self, level, compound, reference - ): + def test_unwrap_no_bonds_exception_safety(self, level, compound, reference): # universe without bonds: u = UnWrapUniverse(have_bonds=False) # select group appropriate for compound: @@ -394,9 +382,7 @@ def test_unwrap_no_molnums_exception_safety(self, level, reference): # store original positions: orig_pos = group.atoms.positions with pytest.raises(NoDataError): - group.unwrap( - compound="molecules", reference=reference, inplace=True - ) + group.unwrap(compound="molecules", reference=reference, inplace=True) assert_array_equal(group.atoms.positions, orig_pos) @@ -421,6 +407,4 @@ def test_uncontiguous(): ) # Ok, let's make it whole again and check that we're good u.atoms.unwrap() - assert_almost_equal( - ref_pos, ag.positions + displacement_vec, decimal=precision - ) + assert_almost_equal(ref_pos, ag.positions + displacement_vec, decimal=precision) diff --git a/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py b/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py index fc41670a6e..3d4ace4cba 100644 --- a/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py +++ b/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py @@ -44,9 +44,7 @@ def ag(self, u): @pytest.fixture() def ag_updating(self, u): - return u.select_atoms( - "prop x < 5 and prop y < 5 and prop z < 5", updating=True - ) + return u.select_atoms("prop x < 5 and prop y < 5 and prop z < 5", updating=True) @pytest.fixture() def ag_updating_compounded(self, u, ag): @@ -54,9 +52,7 @@ def ag_updating_compounded(self, u, ag): @pytest.fixture() def ag_updating_chained(self, u, ag_updating): - return u.select_atoms( - "around 2 group sele", sele=ag_updating, updating=True - ) + return u.select_atoms("around 2 group sele", sele=ag_updating, updating=True) @pytest.fixture() def ag_updating_chained2(self, ag_updating): @@ -91,9 +87,7 @@ def test_update(self, u, ag, ag_updating): assert ag_updating._lastupdate is None def test_compounded_update(self, u, ag_updating_compounded): - target_idxs0 = np.array( - [3650, 7406, 22703, 31426, 40357, 40360, 41414] - ) + target_idxs0 = np.array([3650, 7406, 22703, 31426, 40357, 40360, 41414]) target_idxs1 = np.array( [3650, 8146, 23469, 23472, 31426, 31689, 31692, 34326, 41414] ) @@ -101,13 +95,9 @@ def test_compounded_update(self, u, ag_updating_compounded): next(u.trajectory) assert_equal(ag_updating_compounded.indices, target_idxs1) - def test_chained_update( - self, u, ag_updating_chained, ag_updating_compounded - ): + def test_chained_update(self, u, ag_updating_chained, ag_updating_compounded): target_idxs = np.array([4471, 7406, 11973, 11975, 34662, 44042]) - assert_equal( - ag_updating_chained.indices, ag_updating_compounded.indices - ) + assert_equal(ag_updating_chained.indices, ag_updating_compounded.indices) next(u.trajectory) assert_equal(ag_updating_chained.indices, target_idxs) @@ -295,9 +285,7 @@ def test_representations(): rep = repr(ag_updating) assert "1 atom," in rep - ag_updating = u.atoms[:-1].select_atoms( - "bynum 1", "bynum 2", updating=True - ) + ag_updating = u.atoms[:-1].select_atoms("bynum 1", "bynum 2", updating=True) rep = repr(ag_updating) assert "2 atoms," in rep assert "selections 'bynum 1' + 'bynum 2'" in rep diff --git a/testsuite/MDAnalysisTests/core/test_wrap.py b/testsuite/MDAnalysisTests/core/test_wrap.py index 76b0263a8e..a6e67fb0e2 100644 --- a/testsuite/MDAnalysisTests/core/test_wrap.py +++ b/testsuite/MDAnalysisTests/core/test_wrap.py @@ -58,19 +58,13 @@ def test_wrap_pass(self, level, compound, center, is_triclinic): # get the expected result: ref_wrapped_pos = u.wrapped_coords(compound, center) # first, do the wrapping out-of-place: - wrapped_pos = group.wrap( - compound=compound, center=center, inplace=False - ) + wrapped_pos = group.wrap(compound=compound, center=center, inplace=False) # check for correct result: - assert_almost_equal( - wrapped_pos, ref_wrapped_pos, decimal=self.precision - ) + assert_almost_equal(wrapped_pos, ref_wrapped_pos, decimal=self.precision) # make sure atom positions are unchanged: assert_array_equal(group.atoms.positions, orig_pos) # now, do the wrapping inplace: - wrapped_pos2 = group.wrap( - compound=compound, center=center, inplace=True - ) + wrapped_pos2 = group.wrap(compound=compound, center=center, inplace=True) # check that result is the same as for out-of-place computation: assert_array_equal(wrapped_pos, wrapped_pos2) # check that wrapped positions are applied: @@ -83,9 +77,7 @@ def test_wrap_pass(self, level, compound, center, is_triclinic): compos = group.atoms.center_of_mass(wrap=False, compound=compound) assert_in_box(compos, group.dimensions) else: - cogpos = group.atoms.center_of_geometry( - wrap=False, compound=compound - ) + cogpos = group.atoms.center_of_geometry(wrap=False, compound=compound) assert_in_box(cogpos, group.dimensions) @pytest.mark.parametrize("level", ("atoms", "residues", "segments")) @@ -126,9 +118,7 @@ def test_unwrap_wrap_cycle(self, level, compound, center, is_triclinic): ) @pytest.mark.parametrize("center", ("com", "cog")) @pytest.mark.parametrize("is_triclinic", (False, True)) - def test_wrap_partial_compound( - self, level, compound, center, is_triclinic - ): + def test_wrap_partial_compound(self, level, compound, center, is_triclinic): # get a pristine test universe: u = UnWrapUniverse(is_triclinic=is_triclinic) group = u.atoms @@ -183,9 +173,7 @@ def test_wrap_empty_group(self, level, compound, center, is_triclinic): group = group.segments group.wrap(compound=compound, center=center, inplace=True) # check for correct (empty) result: - assert_array_equal( - group.atoms.positions, np.empty((0, 3), dtype=np.float32) - ) + assert_array_equal(group.atoms.positions, np.empty((0, 3), dtype=np.float32)) @pytest.mark.parametrize("level", ("atoms", "residues", "segments")) @pytest.mark.parametrize( @@ -244,19 +232,13 @@ def test_wrap_com_cog_difference(self, compound, is_triclinic): # the first unit cell in negative x-direction. group.masses = [100.0, 1.0, 1.0] # wrap with center='cog': - wrapped_pos_cog = group.wrap( - compound=compound, center="cog", inplace=False - ) + wrapped_pos_cog = group.wrap(compound=compound, center="cog", inplace=False) # get expected result: ref_wrapped_pos = u.wrapped_coords(compound, "cog")[6:9] # check for correctness: - assert_almost_equal( - wrapped_pos_cog, ref_wrapped_pos, decimal=self.precision - ) + assert_almost_equal(wrapped_pos_cog, ref_wrapped_pos, decimal=self.precision) # wrap with center='com': - wrapped_pos_com = group.wrap( - compound=compound, center="com", inplace=False - ) + wrapped_pos_com = group.wrap(compound=compound, center="com", inplace=False) # assert that the com result is shifted with respect to the cog result # by one box length in the x-direction: shift = np.array([10.0, 0.0, 0.0], dtype=np.float32) diff --git a/testsuite/MDAnalysisTests/core/util.py b/testsuite/MDAnalysisTests/core/util.py index 52b83d64d6..4cbe3d20ca 100644 --- a/testsuite/MDAnalysisTests/core/util.py +++ b/testsuite/MDAnalysisTests/core/util.py @@ -376,9 +376,7 @@ def unwrapped_coords(self, compound, reference): if reference is not None: ref = reference.lower() if ref not in ["com", "cog"]: - raise ValueError( - "Unknown unwrap reference: {}" "".format(reference) - ) + raise ValueError("Unknown unwrap reference: {}" "".format(reference)) comp = compound.lower() if comp not in [ "group", diff --git a/testsuite/MDAnalysisTests/datafiles.py b/testsuite/MDAnalysisTests/datafiles.py index e32807058f..2a4da72977 100644 --- a/testsuite/MDAnalysisTests/datafiles.py +++ b/testsuite/MDAnalysisTests/datafiles.py @@ -389,7 +389,7 @@ "SURFACE_PDB", # 111 FCC lattice topology for NSGrid bug #2345 "SURFACE_TRR", # full precision coordinates for NSGrid bug #2345 "DSSP", # DSSP test suite - "LAMMPSDUMP_non_linear" + "LAMMPSDUMP_non_linear", ] from importlib import resources @@ -397,9 +397,7 @@ _data_ref = resources.files("MDAnalysisTests.data") -WIN_PDB_multiframe = ( - _data_ref / "windows/WIN_nmr_neopetrosiamide.pdb" -).as_posix() +WIN_PDB_multiframe = (_data_ref / "windows/WIN_nmr_neopetrosiamide.pdb").as_posix() WIN_DLP_HISTORY = (_data_ref / "windows/WIN_HISTORY").as_posix() WIN_TRJ = (_data_ref / "windows/WIN_ache.mdcrd").as_posix() WIN_ARC = (_data_ref / "windows/WIN_test.arc").as_posix() @@ -448,9 +446,7 @@ PSF_NAMD = (_data_ref / "namd_cgenff.psf").as_posix() PDB_NAMD = (_data_ref / "namd_cgenff.pdb").as_posix() -PDB_multipole = ( - _data_ref / "water_methane_acetic-acid_ammonia.pdb" -).as_posix() +PDB_multipole = (_data_ref / "water_methane_acetic-acid_ammonia.pdb").as_posix() PSF_NAMD_TRICLINIC = (_data_ref / "SiN_tric_namd.psf").as_posix() DCD_NAMD_TRICLINIC = (_data_ref / "SiN_tric_namd.dcd").as_posix() PSF_NAMD_GBIS = (_data_ref / "adk_closed_NAMD.psf").as_posix() @@ -478,9 +474,7 @@ PDB_mc_gz = (_data_ref / "model_then_cryst.pdb.gz").as_posix() PDB_mc_bz2 = (_data_ref / "model_then_cryst.pdb.bz2").as_posix() PDB_chainidnewres = (_data_ref / "chainIDnewres.pdb.gz").as_posix() -PDB_sameresid_diffresname = ( - _data_ref / "sameresid_diffresname.pdb" -).as_posix() +PDB_sameresid_diffresname = (_data_ref / "sameresid_diffresname.pdb").as_posix() PDB_chainidrepeat = (_data_ref / "chainIDrepeat.pdb.gz").as_posix() PDB_multiframe = (_data_ref / "nmr_neopetrosiamide.pdb").as_posix() PDB_helix = (_data_ref / "A6PA6_alpha.pdb").as_posix() @@ -498,9 +492,7 @@ GRO_large = (_data_ref / "bigbox.gro.bz2").as_posix() GRO_residwrap = (_data_ref / "residwrap.gro").as_posix() GRO_residwrap_0base = (_data_ref / "residwrap_0base.gro").as_posix() -GRO_sameresid_diffresname = ( - _data_ref / "sameresid_diffresname.gro" -).as_posix() +GRO_sameresid_diffresname = (_data_ref / "sameresid_diffresname.gro").as_posix() PDB = (_data_ref / "adk_oplsaa.pdb").as_posix() XTC = (_data_ref / "adk_oplsaa.xtc").as_posix() TRR = (_data_ref / "adk_oplsaa.trr").as_posix() @@ -512,20 +504,12 @@ PDB_xlserial = (_data_ref / "xl_serial.pdb").as_posix() GRO_MEMPROT = (_data_ref / "analysis/YiiP_lipids.gro.gz").as_posix() XTC_MEMPROT = (_data_ref / "analysis/YiiP_lipids.xtc").as_posix() -XTC_multi_frame = ( - _data_ref / "xtc_test_only_10_frame_10_atoms.xtc" -).as_posix() -TRR_multi_frame = ( - _data_ref / "trr_test_only_10_frame_10_atoms.trr" -).as_posix() +XTC_multi_frame = (_data_ref / "xtc_test_only_10_frame_10_atoms.xtc").as_posix() +TRR_multi_frame = (_data_ref / "trr_test_only_10_frame_10_atoms.trr").as_posix() TNG_traj = (_data_ref / "argon_npt_compressed.tng").as_posix() TNG_traj_gro = (_data_ref / "argon_npt_compressed.gro.gz").as_posix() -TNG_traj_uneven_blocks = ( - _data_ref / "argon_npt_compressed_uneven.tng" -).as_posix() -TNG_traj_vels_forces = ( - _data_ref / "argon_npt_compressed_vels_forces.tng" -).as_posix() +TNG_traj_uneven_blocks = (_data_ref / "argon_npt_compressed_uneven.tng").as_posix() +TNG_traj_vels_forces = (_data_ref / "argon_npt_compressed_vels_forces.tng").as_posix() PDB_xvf = (_data_ref / "cobrotoxin.pdb").as_posix() TPR_xvf = (_data_ref / "cobrotoxin.tpr").as_posix() TRR_xvf = (_data_ref / "cobrotoxin.trr").as_posix() @@ -575,23 +559,13 @@ TPR510_bonded = (_data_ref / "tprs/all_bonded/dummy_5.1.tpr").as_posix() TPR2016_bonded = (_data_ref / "tprs/all_bonded/dummy_2016.tpr").as_posix() TPR2018_bonded = (_data_ref / "tprs/all_bonded/dummy_2018.tpr").as_posix() -TPR2019B3_bonded = ( - _data_ref / "tprs/all_bonded/dummy_2019-beta3.tpr" -).as_posix() -TPR2020B2_bonded = ( - _data_ref / "tprs/all_bonded/dummy_2020-beta2.tpr" -).as_posix() +TPR2019B3_bonded = (_data_ref / "tprs/all_bonded/dummy_2019-beta3.tpr").as_posix() +TPR2020B2_bonded = (_data_ref / "tprs/all_bonded/dummy_2020-beta2.tpr").as_posix() TPR2020_bonded = (_data_ref / "tprs/all_bonded/dummy_2020.tpr").as_posix() -TPR2020_double_bonded = ( - _data_ref / "tprs/all_bonded/dummy_2020_double.tpr" -).as_posix() +TPR2020_double_bonded = (_data_ref / "tprs/all_bonded/dummy_2020_double.tpr").as_posix() TPR2021_bonded = (_data_ref / "tprs/all_bonded/dummy_2021.tpr").as_posix() -TPR2021_double_bonded = ( - _data_ref / "tprs/all_bonded/dummy_2021_double.tpr" -).as_posix() -TPR2022RC1_bonded = ( - _data_ref / "tprs/all_bonded/dummy_2022-rc1.tpr" -).as_posix() +TPR2021_double_bonded = (_data_ref / "tprs/all_bonded/dummy_2021_double.tpr").as_posix() +TPR2022RC1_bonded = (_data_ref / "tprs/all_bonded/dummy_2022-rc1.tpr").as_posix() TPR2023_bonded = (_data_ref / "tprs/all_bonded/dummy_2023.tpr").as_posix() TPR2024_bonded = (_data_ref / "tprs/all_bonded/dummy_2024.tpr").as_posix() TPR2024_4_bonded = (_data_ref / "tprs/all_bonded/dummy_2024_4.tpr").as_posix() @@ -724,9 +698,7 @@ mol2_molecule = (_data_ref / "mol2/Molecule.mol2").as_posix() mol2_ligand = (_data_ref / "mol2/Ligand.mol2").as_posix() mol2_broken_molecule = (_data_ref / "mol2/BrokenMolecule.mol2").as_posix() -mol2_comments_header = ( - _data_ref / "mol2/Molecule_comments_header.mol2" -).as_posix() +mol2_comments_header = (_data_ref / "mol2/Molecule_comments_header.mol2").as_posix() # MOL2 file without substructure field mol2_zinc = (_data_ref / "mol2/zinc_856218.mol2").as_posix() # MOL2 file without bonds @@ -737,12 +709,8 @@ capping_ace = (_data_ref / "capping/ace.pdb").as_posix() capping_nma = (_data_ref / "capping/nma.pdb").as_posix() -contacts_villin_folded = ( - _data_ref / "contacts/villin_folded.gro.bz2" -).as_posix() -contacts_villin_unfolded = ( - _data_ref / "contacts/villin_unfolded.gro.bz2" -).as_posix() +contacts_villin_folded = (_data_ref / "contacts/villin_folded.gro.bz2").as_posix() +contacts_villin_unfolded = (_data_ref / "contacts/villin_unfolded.gro.bz2").as_posix() contacts_file = (_data_ref / "contacts/2F4K_qlist5_remap.dat").as_posix() trz4data = (_data_ref / "lammps/datatest.trz").as_posix() @@ -760,24 +728,16 @@ LAMMPSDUMP = (_data_ref / "lammps/wat.lammpstrj.bz2").as_posix() LAMMPSDUMP_long = (_data_ref / "lammps/wat.lammpstrj_long.bz2").as_posix() LAMMPSDUMP_allinfo = (_data_ref / "lammps/mass_q_elem.lammpstrj").as_posix() -LAMMPSDUMP_nomass_elemx = ( - _data_ref / "lammps/nomass_elemx.lammpstrj" -).as_posix() -LAMMPSDUMP_allcoords = ( - _data_ref / "lammps/spce_all_coords.lammpstrj.bz2" -).as_posix() -LAMMPSDUMP_nocoords = ( - _data_ref / "lammps/spce_no_coords.lammpstrj.bz2" -).as_posix() +LAMMPSDUMP_nomass_elemx = (_data_ref / "lammps/nomass_elemx.lammpstrj").as_posix() +LAMMPSDUMP_allcoords = (_data_ref / "lammps/spce_all_coords.lammpstrj.bz2").as_posix() +LAMMPSDUMP_nocoords = (_data_ref / "lammps/spce_no_coords.lammpstrj.bz2").as_posix() LAMMPSDUMP_triclinic = (_data_ref / "lammps/albite_triclinic.dump").as_posix() LAMMPSDUMP_image_vf = (_data_ref / "lammps/image_vf.lammpstrj").as_posix() LAMMPS_image_vf = (_data_ref / "lammps/image_vf.data").as_posix() LAMMPSDUMP_chain1 = (_data_ref / "lammps/chain_dump_1.lammpstrj").as_posix() LAMMPSDUMP_chain2 = (_data_ref / "lammps/chain_dump_2.lammpstrj").as_posix() LAMMPS_chain = (_data_ref / "lammps/chain_initial.data").as_posix() -LAMMPSdata_many_bonds = ( - _data_ref / "lammps/a_lot_of_bond_types.data" -).as_posix() +LAMMPSdata_many_bonds = (_data_ref / "lammps/a_lot_of_bond_types.data").as_posix() LAMMPSdata_additional_columns = ( _data_ref / "lammps/additional_columns.data" ).as_posix() @@ -792,9 +752,7 @@ GMS_ASYMSURF = (_data_ref / "gms/surf2wat.gms").as_posix() two_water_gro = (_data_ref / "two_water_gro.gro").as_posix() -two_water_gro_multiframe = ( - _data_ref / "two_water_gro_multiframe.gro" -).as_posix() +two_water_gro_multiframe = (_data_ref / "two_water_gro_multiframe.gro").as_posix() two_water_gro_nonames = (_data_ref / "two_water_gro_nonames.gro").as_posix() two_water_gro_widebox = (_data_ref / "two_water_gro_widebox.gro").as_posix() @@ -804,9 +762,7 @@ DLP_HISTORY = (_data_ref / "dlpoly/HISTORY").as_posix() DLP_HISTORY_order = (_data_ref / "dlpoly/HISTORY_order").as_posix() DLP_HISTORY_minimal = (_data_ref / "dlpoly/HISTORY_minimal").as_posix() -DLP_HISTORY_minimal_cell = ( - _data_ref / "dlpoly/HISTORY_minimal_cell" -).as_posix() +DLP_HISTORY_minimal_cell = (_data_ref / "dlpoly/HISTORY_minimal_cell").as_posix() DLP_HISTORY_classic = (_data_ref / "dlpoly/HISTORY_classic").as_posix() waterPSF = (_data_ref / "watdyn.psf").as_posix() @@ -855,21 +811,11 @@ TRC_TRAJ2_VAC = (_data_ref / "gromos11/gromos11_traj_vac_2.trc.gz").as_posix() TRC_PDB_SOLV = (_data_ref / "gromos11/gromos11_traj_solv.pdb.gz").as_posix() TRC_TRAJ_SOLV = (_data_ref / "gromos11/gromos11_traj_solv.trc.gz").as_posix() -TRC_CLUSTER_VAC = ( - _data_ref / "gromos11/gromos11_cluster_vac.trj.gz" -).as_posix() -TRC_TRICLINIC_SOLV = ( - _data_ref / "gromos11/gromos11_triclinic_solv.trc.gz" -).as_posix() -TRC_TRUNCOCT_VAC = ( - _data_ref / "gromos11/gromos11_truncOcta_vac.trc.gz" -).as_posix() -TRC_GENBOX_ORIGIN = ( - _data_ref / "gromos11/gromos11_genbox_origin.trc.gz" -).as_posix() -TRC_GENBOX_EULER = ( - _data_ref / "gromos11/gromos11_genbox_euler.trc.gz" -).as_posix() +TRC_CLUSTER_VAC = (_data_ref / "gromos11/gromos11_cluster_vac.trj.gz").as_posix() +TRC_TRICLINIC_SOLV = (_data_ref / "gromos11/gromos11_triclinic_solv.trc.gz").as_posix() +TRC_TRUNCOCT_VAC = (_data_ref / "gromos11/gromos11_truncOcta_vac.trc.gz").as_posix() +TRC_GENBOX_ORIGIN = (_data_ref / "gromos11/gromos11_genbox_origin.trc.gz").as_posix() +TRC_GENBOX_EULER = (_data_ref / "gromos11/gromos11_genbox_euler.trc.gz").as_posix() TRC_EMPTY = (_data_ref / "gromos11/gromos11_empty.trc").as_posix() DihedralArray = (_data_ref / "adk_oplsaa_dihedral.npy").as_posix() @@ -907,7 +853,9 @@ SURFACE_PDB = (_data_ref / "surface.pdb.bz2").as_posix() SURFACE_TRR = (_data_ref / "surface.trr").as_posix() -LAMMPSDUMP_non_linear = (_data_ref / "custom_non_linear/test_non_linear.dump").as_posix() +LAMMPSDUMP_non_linear = ( + _data_ref / "custom_non_linear/test_non_linear.dump" +).as_posix() # DSSP testing: from https://github.com/ShintaroMinami/PyDSSP DSSP = (_data_ref / "dssp").as_posix() diff --git a/testsuite/MDAnalysisTests/dummy.py b/testsuite/MDAnalysisTests/dummy.py index 7bfa11fdb8..860ac0b8f6 100644 --- a/testsuite/MDAnalysisTests/dummy.py +++ b/testsuite/MDAnalysisTests/dummy.py @@ -83,9 +83,7 @@ def make_Universe( n_residues=n_residues, n_segments=n_segments, atom_resindex=np.repeat(np.arange(n_residues), n_atoms // n_residues), - residue_segindex=np.repeat( - np.arange(n_segments), n_residues // n_segments - ), + residue_segindex=np.repeat(np.arange(n_segments), n_residues // n_segments), # trajectory things trajectory=trajectory, velocities=velocities, @@ -154,9 +152,7 @@ def make_types(size): """Atoms are given types TypeA -> TypeE on a loop""" na, nr, ns = size types = itertools.cycle(string.ascii_uppercase[:5]) - return np.array( - ["Type{}".format(next(types)) for _ in range(na)], dtype=object - ) + return np.array(["Type{}".format(next(types)) for _ in range(na)], dtype=object) def make_names(size): diff --git a/testsuite/MDAnalysisTests/formats/test_libdcd.py b/testsuite/MDAnalysisTests/formats/test_libdcd.py index 63a9d83622..fd47b443d7 100644 --- a/testsuite/MDAnalysisTests/formats/test_libdcd.py +++ b/testsuite/MDAnalysisTests/formats/test_libdcd.py @@ -397,16 +397,13 @@ def write_dcd(in_name, out_name, remarks="testing", header=None): @pytest.mark.xfail( - (os.name == "nt" and sys.maxsize <= 2**32) - or platform.machine() == "aarch64", + (os.name == "nt" and sys.maxsize <= 2**32) or platform.machine() == "aarch64", reason="occasional fail on 32-bit windows and ARM", ) # occasionally fails due to unreliable test timings @hypothesis.settings(deadline=None) # see Issue 3096 @given( - remarks=strategies.text( - alphabet=string.printable, min_size=0, max_size=239 - ) + remarks=strategies.text(alphabet=string.printable, min_size=0, max_size=239) ) # handle the printable ASCII strings @example(remarks="") def test_written_remarks_property(remarks, tmpdir_factory): @@ -647,9 +644,7 @@ def test_readframes_order(order, shape, dcd): assert x.shape == shape -@pytest.mark.parametrize( - "indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]] -) +@pytest.mark.parametrize("indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]]) def test_readframes_atomindices(indices, dcd): allframes = dcd.readframes(order="afc").xyz frames = dcd.readframes(indices=indices, order="afc") diff --git a/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py b/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py index 64748e3088..23eb6536d3 100644 --- a/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py +++ b/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py @@ -497,9 +497,7 @@ def test_write_trr_dtype(tmpdir, dtype, trr): v = frame.v.astype(dtype) f = frame.f.astype(dtype) box = frame.box.astype(dtype) - fout.write( - x, v, f, box, frame.step, frame.time, frame.lmbda, natoms - ) + fout.write(x, v, f, box, frame.step, frame.time, frame.lmbda, natoms) @pytest.mark.parametrize("array_like", (np.array, list)) @@ -512,9 +510,7 @@ def test_write_trr_array_like(tmpdir, array_like, trr): v = array_like(frame.v) f = array_like(frame.f) box = array_like(frame.box) - fout.write( - x, v, f, box, frame.step, frame.time, frame.lmbda, natoms - ) + fout.write(x, v, f, box, frame.step, frame.time, frame.lmbda, natoms) def test_write_different_box_trr(tmpdir, trr): diff --git a/testsuite/MDAnalysisTests/guesser/test_base.py b/testsuite/MDAnalysisTests/guesser/test_base.py index e890ca9957..b22246d99d 100644 --- a/testsuite/MDAnalysisTests/guesser/test_base.py +++ b/testsuite/MDAnalysisTests/guesser/test_base.py @@ -58,16 +58,13 @@ class TestGuesser1(GuesserBase): def test_guess_invalid_attribute(self): with pytest.raises( ValueError, - match="default guesser can not guess " - "the following attribute: foo", + match="default guesser can not guess " "the following attribute: foo", ): mda.Universe(datafiles.PDB_xsmall, to_guess=["foo"]) def test_guess_attribute_with_missing_parent_attr(self): names = Atomnames(np.array(["C", "HB", "HA", "O"], dtype=object)) - masses = Masses( - np.array([np.nan, np.nan, np.nan, np.nan], dtype=np.float64) - ) + masses = Masses(np.array([np.nan, np.nan, np.nan, np.nan], dtype=np.float64)) top = Topology(4, 1, 1, attrs=[names, masses]) u = mda.Universe(top, to_guess=["masses"]) assert_allclose( @@ -88,9 +85,7 @@ def test_partial_guessing(self): masses = Masses(np.array([0, np.nan, np.nan, 0], dtype=np.float64)) top = Topology(4, 1, 1, attrs=[types, masses]) u = mda.Universe(top, to_guess=["masses"]) - assert_allclose( - u.atoms.masses, np.array([0, 1.00800, 1.00800, 0]), atol=0 - ) + assert_allclose(u.atoms.masses, np.array([0, 1.00800, 1.00800, 0]), atol=0) def test_force_guess_priority(self): "check that passing the attribute to force_guess have higher power" @@ -185,9 +180,7 @@ def test_guess_topology_objects_out_of_order_guess(self): with pytest.raises(NoDataError): u.atoms.angles - u.guess_TopologyAttrs( - "default", to_guess=["dihedrals", "angles", "bonds"] - ) + u.guess_TopologyAttrs("default", to_guess=["dihedrals", "angles", "bonds"]) assert len(u.atoms.angles) == 290 assert len(u.atoms.dihedrals) == 411 @@ -249,9 +242,7 @@ def test_guess_singular(self): def test_Universe_guess_bonds_deprecated(): - with pytest.warns( - DeprecationWarning, match="`guess_bonds` keyword is deprecated" - ): + with pytest.warns(DeprecationWarning, match="`guess_bonds` keyword is deprecated"): u = mda.Universe(datafiles.PDB_xsmall, guess_bonds=True) diff --git a/testsuite/MDAnalysisTests/guesser/test_default_guesser.py b/testsuite/MDAnalysisTests/guesser/test_default_guesser.py index 92c24593c3..9aa6c2e27e 100644 --- a/testsuite/MDAnalysisTests/guesser/test_default_guesser.py +++ b/testsuite/MDAnalysisTests/guesser/test_default_guesser.py @@ -57,9 +57,7 @@ def test_guess_masses_from_universe(self): u = mda.Universe(topology) assert isinstance(u.atoms.masses, np.ndarray) - assert_allclose( - u.atoms.masses, np.array([12.011, 12.011, 1.008]), atol=0 - ) + assert_allclose(u.atoms.masses, np.array([12.011, 12.011, 1.008]), atol=0) def test_guess_masses_from_guesser_object(self, default_guesser): elements = ["H", "Ca", "Am"] @@ -90,9 +88,7 @@ def test_guess_atom_mass(self, default_guesser): def test_guess_masses_with_no_reference_elements(self): u = mda.Universe.empty(3) - with pytest.raises( - NoDataError, match=("there is no reference attributes ") - ): + with pytest.raises(NoDataError, match=("there is no reference attributes ")): u.guess_TopologyAttrs("default", ["masses"]) @@ -127,10 +123,7 @@ def test_partial_guess_elements(self, default_guesser): def test_guess_elements_from_no_data(self): top = Topology(5) - msg = ( - "there is no reference attributes in this " - "universe to guess types from" - ) + msg = "there is no reference attributes in this " "universe to guess types from" with pytest.warns(UserWarning, match=msg): mda.Universe(top, to_guess=["types"]) @@ -212,9 +205,7 @@ def test_guess_dihedrals_with_no_angles(): def test_guess_impropers_with_angles(): "Test guessing impropers for atoms with angles" "and bonds information " - u = mda.Universe( - datafiles.two_water_gro, to_guess=["bonds", "angles", "impropers"] - ) + u = mda.Universe(datafiles.two_water_gro, to_guess=["bonds", "angles", "impropers"]) u.guess_TopologyAttrs(to_guess=["impropers"]) assert hasattr(u, "impropers") assert hasattr(u, "angles") @@ -245,16 +236,12 @@ def bond_sort(arr): def test_guess_bonds_water(): u = mda.Universe(datafiles.two_water_gro) bonds = bond_sort( - DefaultGuesser(None, box=u.dimensions).guess_bonds( - u.atoms, u.atoms.positions - ) + DefaultGuesser(None, box=u.dimensions).guess_bonds(u.atoms, u.atoms.positions) ) assert_equal(bonds, ((0, 1), (0, 2), (3, 4), (3, 5))) -@pytest.mark.parametrize( - "fudge_factor, n_bonds", [(0, 0), (0.55, 4), (200, 6)] -) +@pytest.mark.parametrize("fudge_factor, n_bonds", [(0, 0), (0.55, 4), (200, 6)]) def test_guess_bonds_water_fudge_factor_passed(fudge_factor, n_bonds): u = mda.Universe( datafiles.two_water_gro, @@ -330,8 +317,6 @@ def test_guess_gasteiger_charges(smi): @requires_rdkit def test_aromaticity(): - u = mda.Universe( - datafiles.PDB_small, to_guess=["elements", "aromaticities"] - ) + u = mda.Universe(datafiles.PDB_small, to_guess=["elements", "aromaticities"]) c_aromatic = u.select_atoms("resname PHE and name CD1") assert_equal(c_aromatic.aromaticities[0], True) diff --git a/testsuite/MDAnalysisTests/lib/test_cutil.py b/testsuite/MDAnalysisTests/lib/test_cutil.py index 47c4d7f905..d583551881 100644 --- a/testsuite/MDAnalysisTests/lib/test_cutil.py +++ b/testsuite/MDAnalysisTests/lib/test_cutil.py @@ -99,7 +99,5 @@ def test_in2d(): ], ) def test_in2d_VE(arr1, arr2): - with pytest.raises( - ValueError, match=r"Both arrays must be \(n, 2\) arrays" - ): + with pytest.raises(ValueError, match=r"Both arrays must be \(n, 2\) arrays"): _in2d(arr1, arr2) diff --git a/testsuite/MDAnalysisTests/lib/test_distances.py b/testsuite/MDAnalysisTests/lib/test_distances.py index 06abe0a99c..6d93ff3fbe 100644 --- a/testsuite/MDAnalysisTests/lib/test_distances.py +++ b/testsuite/MDAnalysisTests/lib/test_distances.py @@ -63,9 +63,7 @@ def test_check_result_array_wrong_dtype(self): wrong_dtype = np.int64 ref_wrong_dtype = self.ref.astype(wrong_dtype) with pytest.raises(TypeError) as err: - res = distances._check_result_array( - ref_wrong_dtype, self.ref.shape - ) + res = distances._check_result_array(ref_wrong_dtype, self.ref.shape) assert err.msg == ( "Result array must be of type numpy.float64, " "got {}.".format(wrong_dtype) @@ -126,9 +124,7 @@ def test_capped_distance_noresults(self): point1 = np.array([0.1, 0.1, 0.1], dtype=np.float32) point2 = np.array([0.95, 0.1, 0.1], dtype=np.float32) - pairs, dists = distances.capped_distance( - point1, point2, max_cutoff=0.2 - ) + pairs, dists = distances.capped_distance(point1, point2, max_cutoff=0.2) assert_equal(len(pairs), 0) @@ -311,9 +307,9 @@ def test_self_capped_distance( ) def test_method_selfselection(self, box, npoints, cutoff, meth): np.random.seed(90003) - points = ( - np.random.uniform(low=0, high=1.0, size=(npoints, 3)) - ).astype(np.float32) + points = (np.random.uniform(low=0, high=1.0, size=(npoints, 3))).astype( + np.float32 + ) method = distances._determine_method_self(points, cutoff, box=box) assert_equal(method.__name__, meth) @@ -408,9 +404,7 @@ def test_noPBC(self, backend, ref_system, pos, request): # cycle through combinations of numpy array and AtomGroup @pytest.mark.parametrize("pos0", ["ref_system", "ref_system_universe"]) @pytest.mark.parametrize("pos1", ["ref_system", "ref_system_universe"]) - def test_noPBC_mixed_combinations( - self, backend, ref_system, pos0, pos1, request - ): + def test_noPBC_mixed_combinations(self, backend, ref_system, pos0, pos1, request): _, points, reference, _ = ref_system # reference values _, _, ref_val, _ = request.getfixturevalue(pos0) _, points_val, _, _ = request.getfixturevalue(pos1) @@ -445,15 +439,11 @@ def test_PBC(self, backend, ref_system, pos, request): # cycle through combinations of numpy array and AtomGroup @pytest.mark.parametrize("pos0", ["ref_system", "ref_system_universe"]) @pytest.mark.parametrize("pos1", ["ref_system", "ref_system_universe"]) - def test_PBC_mixed_combinations( - self, backend, ref_system, pos0, pos1, request - ): + def test_PBC_mixed_combinations(self, backend, ref_system, pos0, pos1, request): box, points, _, _ = ref_system _, _, ref_val, _ = request.getfixturevalue(pos0) _, points_val, _, _ = request.getfixturevalue(pos1) - d = distances.distance_array( - ref_val, points_val, box=box, backend=backend - ) + d = distances.distance_array(ref_val, points_val, box=box, backend=backend) assert_almost_equal( d, np.array([[0.0, 0.0, 0.0, self._dist(points[3], ref=[1, 1, 2])]]), @@ -542,9 +532,7 @@ def test_simple(self, DCD_Universe, backend): trajectory[10] x1 = U.atoms.positions d = distances.distance_array(x0, x1, backend=backend) - assert_equal( - d.shape, (3341, 3341), "wrong shape (should be" "(Natoms,Natoms))" - ) + assert_equal(d.shape, (3341, 3341), "wrong shape (should be" "(Natoms,Natoms))") assert_almost_equal( d.min(), 0.11981228170520701, @@ -594,9 +582,7 @@ def test_periodic(self, DCD_Universe, backend): x0 = U.atoms.positions trajectory[10] x1 = U.atoms.positions - d = distances.distance_array( - x0, x1, box=U.coord.dimensions, backend=backend - ) + d = distances.distance_array(x0, x1, box=U.coord.dimensions, backend=backend) assert_equal( d.shape, (3341, 3341), @@ -653,18 +639,14 @@ def test_atomgroup_simple(self, DCD_Universe, DCD_Universe2, backend): ("index 9", np.s_[8, :]), ], ) - def test_atomgroup_matches_numpy( - self, DCD_Universe, backend, sel, np_slice, box - ): + def test_atomgroup_matches_numpy(self, DCD_Universe, backend, sel, np_slice, box): U = DCD_Universe x0_ag = U.select_atoms(sel) x0_arr = U.atoms.positions[np_slice] x1_ag = U.select_atoms(sel) x1_arr = U.atoms.positions[np_slice] d_ag = distances.distance_array(x0_ag, x1_ag, box=box, backend=backend) - d_arr = distances.distance_array( - x0_arr, x1_arr, box=box, backend=backend - ) + d_arr = distances.distance_array(x0_arr, x1_arr, box=box, backend=backend) assert_allclose( d_ag, d_arr, err_msg="AtomGroup and NumPy distances do not match" ) @@ -708,9 +690,7 @@ def test_simple(self, DCD_Universe, backend): x0 = U.atoms.positions d = distances.self_distance_array(x0, backend=backend) N = 3341 * (3341 - 1) / 2 - assert_equal( - d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))" - ) + assert_equal(d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))") assert_almost_equal( d.min(), 0.92905562402529318, @@ -733,9 +713,7 @@ def test_outarray(self, DCD_Universe, backend): N = natoms * (natoms - 1) // 2 d = np.zeros((N,), np.float64) distances.self_distance_array(x0, result=d, backend=backend) - assert_equal( - d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))" - ) + assert_equal(d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))") assert_almost_equal( d.min(), 0.92905562402529318, @@ -757,12 +735,8 @@ def test_periodic(self, DCD_Universe, backend): x0 = U.atoms.positions natoms = len(U.atoms) N = natoms * (natoms - 1) / 2 - d = distances.self_distance_array( - x0, box=U.coord.dimensions, backend=backend - ) - assert_equal( - d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))" - ) + d = distances.self_distance_array(x0, box=U.coord.dimensions, backend=backend) + assert_equal(d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))") assert_almost_equal( d.min(), 0.92905562402529318, @@ -783,9 +757,7 @@ def test_atomgroup_simple(self, DCD_Universe, backend): x0 = U.select_atoms("all") d = distances.self_distance_array(x0, backend=backend) N = 3341 * (3341 - 1) / 2 - assert_equal( - d.shape, (N,), "wrong shape (should be" " (Natoms*(Natoms-1)/2,))" - ) + assert_equal(d.shape, (N,), "wrong shape (should be" " (Natoms*(Natoms-1)/2,))") assert_almost_equal( d.min(), 0.92905562402529318, @@ -809,9 +781,7 @@ def test_atomgroup_simple(self, DCD_Universe, backend): ("index 9", np.s_[8, :]), ], ) - def test_atomgroup_matches_numpy( - self, DCD_Universe, backend, sel, np_slice, box - ): + def test_atomgroup_matches_numpy(self, DCD_Universe, backend, sel, np_slice, box): U = DCD_Universe x0_ag = U.select_atoms(sel) @@ -936,9 +906,7 @@ def test_selfdist(self, S_mol, box, tri_vec_box, backend): # distopia backend support R_coords = distances.transform_StoR(S_mol1, box, backend="serial") # Transform functions are tested elsewhere so taken as working here - dists = distances.self_distance_array( - R_coords, box=box, backend=backend - ) + dists = distances.self_distance_array(R_coords, box=box, backend=backend) # Manually calculate self_distance_array manual = np.zeros(len(dists), dtype=np.float64) distpos = 0 @@ -964,9 +932,7 @@ def test_selfdist(self, S_mol, box, tri_vec_box, backend): # distopia backend support R_coords = distances.transform_StoR(S_mol2, box, backend="serial") # Transform functions are tested elsewhere so taken as working here - dists = distances.self_distance_array( - R_coords, box=box, backend=backend - ) + dists = distances.self_distance_array(R_coords, box=box, backend=backend) # Manually calculate self_distance_array manual = np.zeros(len(dists), dtype=np.float64) distpos = 0 @@ -996,9 +962,7 @@ def test_distarray(self, S_mol, tri_vec_box, box, backend): R_mol2 = distances.transform_StoR(S_mol2, box, backend="serial") # Try with box - dists = distances.distance_array( - R_mol1, R_mol2, box=box, backend=backend - ) + dists = distances.distance_array(R_mol1, R_mol2, box=box, backend=backend) # Manually calculate distance_array manual = np.zeros((len(R_mol1), len(R_mol2))) for i, Ri in enumerate(R_mol1): @@ -1018,9 +982,7 @@ def test_distarray(self, S_mol, tri_vec_box, box, backend): def test_pbc_dist(self, S_mol, box, backend): S_mol1, S_mol2 = S_mol results = np.array([[37.629944]]) - dists = distances.distance_array( - S_mol1, S_mol2, box=box, backend=backend - ) + dists = distances.distance_array(S_mol1, S_mol2, box=box, backend=backend) assert_almost_equal( dists, @@ -1036,9 +998,7 @@ def test_pbc_wrong_wassenaar_distance(self, backend): a, b, c = tri_vec_box point_a = a + b point_b = 0.5 * point_a - dist = distances.distance_array( - point_a, point_b, box=box, backend=backend - ) + dist = distances.distance_array(point_a, point_b, box=box, backend=backend) assert_almost_equal(dist[0, 0], 1) # check that our distance is different from the wassenaar distance as # expected. @@ -1185,8 +1145,7 @@ def positions_atomgroups(positions): a, b, c, d = positions arrs = [a, b, c, d] universes = [ - MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) - for arr in arrs + MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) for arr in arrs ] for u, a in zip(universes, arrs): u.atoms.positions = a @@ -1213,9 +1172,7 @@ def test_bonds(self, box, backend, dtype, pos, request): a, b, c, d = request.getfixturevalue(pos) a, b, c, d = convert_position_dtype_if_ndarray(a, b, c, d, dtype) dists = distances.calc_bonds(a, b, backend=backend) - assert_equal( - len(dists), 4, err_msg="calc_bonds results have wrong length" - ) + assert_equal(len(dists), 4, err_msg="calc_bonds results have wrong length") dists_pbc = distances.calc_bonds(a, b, box=box, backend=backend) # tests 0 length assert_almost_equal( @@ -1294,9 +1251,7 @@ def test_bonds_badresult(self, positions, backend): @pytest.mark.parametrize("dtype", (np.float32, np.float64)) @pytest.mark.parametrize("pos", ["positions", "positions_atomgroups"]) @pytest.mark.parametrize("backend", distopia_conditional_backend()) - def test_bonds_triclinic( - self, triclinic_box, backend, dtype, pos, request - ): + def test_bonds_triclinic(self, triclinic_box, backend, dtype, pos, request): a, b, c, d = request.getfixturevalue(pos) a, b, c, d = convert_position_dtype_if_ndarray(a, b, c, d, dtype) dists = distances.calc_bonds(a, b, box=triclinic_box, backend=backend) @@ -1322,9 +1277,7 @@ def test_bonds_single_coords(self, shift, periodic, backend): coords[1] += shift2 * box[:3] box = box if periodic else None - result = distances.calc_bonds( - coords[0], coords[1], box, backend=backend - ) + result = distances.calc_bonds(coords[0], coords[1], box, backend=backend) reference = 2.0 if periodic else np.linalg.norm(coords[0] - coords[1]) @@ -1338,9 +1291,7 @@ def test_angles(self, backend, dtype, pos, request): a, b, c, d = convert_position_dtype_if_ndarray(a, b, c, d, dtype) angles = distances.calc_angles(a, b, c, backend=backend) # Check calculated values - assert_equal( - len(angles), 4, err_msg="calc_angles results have wrong length" - ) + assert_equal(len(angles), 4, err_msg="calc_angles results have wrong length") # assert_almost_equal(angles[0], 0.0, self.prec, # err_msg="Zero length angle calculation failed") # What should this be? assert_almost_equal( @@ -1476,9 +1427,7 @@ def test_calc_dihedrals_results_inplace_all_backends( c3[:, 1] = 3 result = np.zeros(N, dtype=np.float64) - distances.calc_dihedrals( - c0, c1, c2, c3, result=result, backend=backend - ) + distances.calc_dihedrals(c0, c1, c2, c3, result=result, backend=backend) expected = np.ones(N, dtype=dtype) * 0 # test the result array is updated in place assert_almost_equal( @@ -1509,9 +1458,7 @@ def test_dihedrals_bad_result(self, positions, backend): badresult = np.zeros(len(a) - 1) # Bad result array with pytest.raises(ValueError): - distances.calc_dihedrals( - a, b, c, d, result=badresult, backend=backend - ) + distances.calc_dihedrals(a, b, c, d, result=badresult, backend=backend) @pytest.mark.parametrize( "case", @@ -1604,9 +1551,7 @@ def test_numpy_compliance_angles(self, positions, backend): angles = distances.calc_angles(a, b, c, backend=backend) vec1 = a - b vec2 = c - b - angles_numpy = np.array( - [mdamath.angle(x, y) for x, y in zip(vec1, vec2)] - ) + angles_numpy = np.array([mdamath.angle(x, y) for x, y in zip(vec1, vec2)]) # numpy 0 angle returns NaN rather than 0 assert_almost_equal( angles[1:], @@ -1677,9 +1622,7 @@ def test_ortho_PBC(self, backend, pos, request, DCD_universe_pos): with pytest.raises(ValueError): cyth1 = distances.apply_PBC(positions, box[:3], backend=backend) cyth2 = distances.apply_PBC(positions, box, backend=backend) - reference = ( - DCD_universe_pos - np.floor(DCD_universe_pos / box[:3]) * box[:3] - ) + reference = DCD_universe_pos - np.floor(DCD_universe_pos / box[:3]) * box[:3] assert_almost_equal( cyth2, @@ -1843,9 +1786,7 @@ def test_dihedrals(self, positions, backend): test2 = distances.calc_dihedrals(a, b2, c, d, box=box, backend=backend) test3 = distances.calc_dihedrals(a, b, c2, d, box=box, backend=backend) test4 = distances.calc_dihedrals(a, b, c, d2, box=box, backend=backend) - test5 = distances.calc_dihedrals( - a2, b2, c2, d2, box=box, backend=backend - ) + test5 = distances.calc_dihedrals(a2, b2, c2, d2, box=box, backend=backend) for val in [test1, test2, test3, test4, test5]: assert_almost_equal( @@ -1892,8 +1833,7 @@ def coords(): @pytest.fixture() def coords_atomgroups(coords): universes = [ - MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) - for arr in coords + MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) for arr in coords ] for u, a in zip(universes, coords): u.atoms.positions = a @@ -1904,9 +1844,7 @@ def coords_atomgroups(coords): def test_input_unchanged_distance_array(self, coords, box, backend): crds = coords[:2] refs = [crd.copy() for crd in crds] - res = distances.distance_array( - crds[0], crds[1], box=box, backend=backend - ) + res = distances.distance_array(crds[0], crds[1], box=box, backend=backend) assert_equal(crds, refs) @pytest.mark.parametrize("box", boxes) @@ -1916,9 +1854,7 @@ def test_input_unchanged_distance_array_atomgroup( ): crds = coords_atomgroups[:2] refs = [crd.positions.copy() for crd in crds] - res = distances.distance_array( - crds[0], crds[1], box=box, backend=backend - ) + res = distances.distance_array(crds[0], crds[1], box=box, backend=backend) assert_equal([crd.positions for crd in crds], refs) @pytest.mark.parametrize("box", boxes) @@ -1958,9 +1894,7 @@ def test_input_unchanged_capped_distance(self, coords, box, met, backend): @pytest.mark.parametrize("box", boxes) @pytest.mark.parametrize("met", ["bruteforce", "pkdtree", "nsgrid", None]) @pytest.mark.parametrize("backend", distopia_conditional_backend()) - def test_input_unchanged_self_capped_distance( - self, coords, box, met, backend - ): + def test_input_unchanged_self_capped_distance(self, coords, box, met, backend): crd = coords[0] ref = crd.copy() r_cut = 0.25 @@ -1971,9 +1905,7 @@ def test_input_unchanged_self_capped_distance( @pytest.mark.parametrize("box", boxes[:2]) @pytest.mark.parametrize("backend", ["serial", "openmp"]) - def test_input_unchanged_transform_RtoS_and_StoR( - self, coords, box, backend - ): + def test_input_unchanged_transform_RtoS_and_StoR(self, coords, box, backend): crd = coords[0] ref = crd.copy() res = distances.transform_RtoS(crd, box, backend=backend) @@ -2006,9 +1938,7 @@ def test_input_unchanged_calc_bonds_atomgroup( def test_input_unchanged_calc_angles(self, coords, box, backend): crds = coords[:3] refs = [crd.copy() for crd in crds] - res = distances.calc_angles( - crds[0], crds[1], crds[2], box=box, backend=backend - ) + res = distances.calc_angles(crds[0], crds[1], crds[2], box=box, backend=backend) assert_equal(crds, refs) @pytest.mark.parametrize("box", boxes) @@ -2018,9 +1948,7 @@ def test_input_unchanged_calc_angles_atomgroup( ): crds = coords_atomgroups[:3] refs = [crd.positions.copy() for crd in crds] - res = distances.calc_angles( - crds[0], crds[1], crds[2], box=box, backend=backend - ) + res = distances.calc_angles(crds[0], crds[1], crds[2], box=box, backend=backend) assert_equal([crd.positions for crd in crds], refs) @pytest.mark.parametrize("box", boxes) @@ -2055,9 +1983,7 @@ def test_input_unchanged_apply_PBC(self, coords, box, backend): @pytest.mark.parametrize("box", boxes[:2]) @pytest.mark.parametrize("backend", ["serial", "openmp"]) - def test_input_unchanged_apply_PBC_atomgroup( - self, coords_atomgroups, box, backend - ): + def test_input_unchanged_apply_PBC_atomgroup(self, coords_atomgroups, box, backend): crd = coords_atomgroups[0] ref = crd.positions.copy() res = distances.apply_PBC(crd, box, backend=backend) @@ -2105,9 +2031,7 @@ def test_empty_input_distance_array(self, empty_coord, box, backend): @pytest.mark.parametrize("box", boxes) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_empty_input_self_distance_array(self, empty_coord, box, backend): - res = distances.self_distance_array( - empty_coord, box=box, backend=backend - ) + res = distances.self_distance_array(empty_coord, box=box, backend=backend) assert_equal(res, np.empty((0,), dtype=np.float64)) @pytest.mark.parametrize("box", boxes) @@ -2172,9 +2096,7 @@ def test_empty_input_transform_StoR(self, empty_coord, box, backend): @pytest.mark.parametrize("box", boxes) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_empty_input_calc_bonds(self, empty_coord, box, backend): - res = distances.calc_bonds( - empty_coord, empty_coord, box=box, backend=backend - ) + res = distances.calc_bonds(empty_coord, empty_coord, box=box, backend=backend) assert_equal(res, np.empty((0,), dtype=np.float64)) @pytest.mark.parametrize("box", boxes) @@ -2354,9 +2276,7 @@ def test_output_dtype_transform_RtoS(self, incoords, box, backend): assert res.shape == incoords.shape @pytest.mark.parametrize("box", boxes) - @pytest.mark.parametrize( - "incoords", [2 * [coords[0]]] + list(comb(coords[1:], 2)) - ) + @pytest.mark.parametrize("incoords", [2 * [coords[0]]] + list(comb(coords[1:], 2))) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_output_type_calc_bonds(self, incoords, box, backend): res = distances.calc_bonds(*incoords, box=box, backend=backend) @@ -2370,9 +2290,7 @@ def test_output_type_calc_bonds(self, incoords, box, backend): assert res.shape == (coord.shape[0],) @pytest.mark.parametrize("box", boxes) - @pytest.mark.parametrize( - "incoords", [3 * [coords[0]]] + list(comb(coords[1:], 3)) - ) + @pytest.mark.parametrize("incoords", [3 * [coords[0]]] + list(comb(coords[1:], 3))) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_output_type_calc_angles(self, incoords, box, backend): res = distances.calc_angles(*incoords, box=box, backend=backend) @@ -2386,9 +2304,7 @@ def test_output_type_calc_angles(self, incoords, box, backend): assert res.shape == (coord.shape[0],) @pytest.mark.parametrize("box", boxes) - @pytest.mark.parametrize( - "incoords", [4 * [coords[0]]] + list(comb(coords[1:], 4)) - ) + @pytest.mark.parametrize("incoords", [4 * [coords[0]]] + list(comb(coords[1:], 4))) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_output_type_calc_dihedrals(self, incoords, box, backend): res = distances.calc_dihedrals(*incoords, box=box, backend=backend) diff --git a/testsuite/MDAnalysisTests/lib/test_neighborsearch.py b/testsuite/MDAnalysisTests/lib/test_neighborsearch.py index 29a179350d..50a118ef7d 100644 --- a/testsuite/MDAnalysisTests/lib/test_neighborsearch.py +++ b/testsuite/MDAnalysisTests/lib/test_neighborsearch.py @@ -42,9 +42,7 @@ def test_search(universe): """simply check that for a centered protein in a large box periodic and non-periodic return the same result""" ns = NeighborSearch.AtomNeighborSearch(universe.atoms) - pns = NeighborSearch.AtomNeighborSearch( - universe.atoms, universe.atoms.dimensions - ) + pns = NeighborSearch.AtomNeighborSearch(universe.atoms, universe.atoms.dimensions) ns_res = ns.search(universe.atoms[20], 20) pns_res = pns.search(universe.atoms[20], 20) diff --git a/testsuite/MDAnalysisTests/lib/test_nsgrid.py b/testsuite/MDAnalysisTests/lib/test_nsgrid.py index 582e780172..bde9b1079f 100644 --- a/testsuite/MDAnalysisTests/lib/test_nsgrid.py +++ b/testsuite/MDAnalysisTests/lib/test_nsgrid.py @@ -134,9 +134,7 @@ def test_nsgrid_PBC_rect(): cutoff = 7 # FastNS is called differently to max coverage - searcher = nsgrid.FastNS( - cutoff, universe.atoms.positions, box=universe.dimensions - ) + searcher = nsgrid.FastNS(cutoff, universe.atoms.positions, box=universe.dimensions) results_grid = searcher.search( universe.atoms.positions[ref_id][None, :] @@ -208,9 +206,7 @@ def test_nsgrid_pairs(universe): results_grid = run_grid_search(universe, ref_id).get_pairs() - assert_equal( - np.sort(neighbors, axis=0), np.sort(results_grid[:, 1], axis=0) - ) + assert_equal(np.sort(neighbors, axis=0), np.sort(results_grid[:, 1], axis=0)) def test_nsgrid_pair_distances(universe): @@ -284,9 +280,9 @@ def test_nsgrid_distances(universe): ) def test_nsgrid_search(box, results): np.random.seed(90003) - points = ( - np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0) - ).astype(np.float32) + points = (np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0)).astype( + np.float32 + ) cutoff = 2.0 query = np.array([1.0, 1.0, 1.0], dtype=np.float32).reshape((1, 3)) @@ -320,9 +316,9 @@ def test_nsgrid_search(box, results): ) def test_nsgrid_selfsearch(box, result): np.random.seed(90003) - points = ( - np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0) - ).astype(np.float32) + points = (np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0)).astype( + np.float32 + ) cutoff = 1.0 if box is None or np.allclose(box[:3], 0): # create a pseudobox @@ -350,9 +346,7 @@ def test_nsgrid_probe_close_to_box_boundary(): # coordinate prior to PR #2136, so we ensure that this remains fixed. # See Issue #2132 for further information. ref = np.array([[55.783722, 44.190044, -54.16671]], dtype=np.float32) - box = np.array( - [53.785854, 43.951054, 57.17597, 90.0, 90.0, 90.0], dtype=np.float32 - ) + box = np.array([53.785854, 43.951054, 57.17597, 90.0, 90.0, 90.0], dtype=np.float32) cutoff = 3.0 # search within a configuration where we know the expected outcome: conf = np.ones((1, 3), dtype=np.float32) @@ -432,9 +426,7 @@ def test_issue_2229_part2(): u.atoms[0].position = [0, 0, 29.29] u.atoms[1].position = [0, 0, 28.23] - g = mda.lib.nsgrid.FastNS( - 3.0, u.atoms[[0]].positions, box=u.dimensions, pbc=False - ) + g = mda.lib.nsgrid.FastNS(3.0, u.atoms[[0]].positions, box=u.dimensions, pbc=False) assert len(g.search(u.atoms[[1]].positions).get_pairs()) == 1 g = mda.lib.nsgrid.FastNS(3.0, u.atoms[[1]].positions, box=u.dimensions) @@ -526,9 +518,9 @@ def high_mem_tests_enabled(): @pytest.mark.skipif(not high_mem_tests_enabled(), reason=reason) def test_issue_3183(): np.random.seed(90003) - points = ( - np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0) - ).astype(np.float32) + points = (np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0)).astype( + np.float32 + ) cutoff = 2.0 query = np.array([1.0, 1.0, 1.0], dtype=np.float32).reshape((1, 3)) box = np.array([10000.0, 10000.0, 10000.0, 90.0, 90.0, 90.0]) diff --git a/testsuite/MDAnalysisTests/lib/test_util.py b/testsuite/MDAnalysisTests/lib/test_util.py index 5db9b9afd4..0f9e357e4a 100644 --- a/testsuite/MDAnalysisTests/lib/test_util.py +++ b/testsuite/MDAnalysisTests/lib/test_util.py @@ -282,18 +282,14 @@ def test_norm_range(self, x): v = r * np.array([np.cos(x), np.sin(x), 0]) assert_almost_equal(mdamath.norm(v), r, 6) - @pytest.mark.parametrize( - "vec1, vec2, value", [(e1, e2, e3), (e1, null, 0.0)] - ) + @pytest.mark.parametrize("vec1, vec2, value", [(e1, e2, e3), (e1, null, 0.0)]) def test_normal(self, vec1, vec2, value): assert_allclose(mdamath.normal(vec1, vec2), value) # add more non-trivial tests def test_angle_lower_clip(self): a = np.array([0.1, 0, 0.2]) - x = np.dot(a**0.5, -(a**0.5)) / ( - mdamath.norm(a**0.5) * mdamath.norm(-(a**0.5)) - ) + x = np.dot(a**0.5, -(a**0.5)) / (mdamath.norm(a**0.5) * mdamath.norm(-(a**0.5))) assert x < -1.0 assert mdamath.angle(a, -(a)) == np.pi assert mdamath.angle(a**0.5, -(a**0.5)) == np.pi @@ -383,9 +379,7 @@ def ref_tribox(self, tri_vecs): return box @pytest.mark.parametrize("lengths", comb_wr([-1, 0, 1, 2], 3)) - @pytest.mark.parametrize( - "angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3) - ) + @pytest.mark.parametrize("angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3)) def test_triclinic_vectors(self, lengths, angles): box = lengths + angles ref = self.ref_trivecs(box) @@ -461,9 +455,7 @@ def test_triclinic_vectors_box_cycle(self): for b in range(10, 91, 10): for g in range(10, 91, 10): ref = np.array([1, 1, 1, a, b, g], dtype=np.float32) - res = mdamath.triclinic_box( - *mdamath.triclinic_vectors(ref) - ) + res = mdamath.triclinic_box(*mdamath.triclinic_vectors(ref)) if not np.all(res == 0.0): assert_almost_equal(res, ref, 5) @@ -486,9 +478,7 @@ def test_triclinic_vectors_box_cycle_exact(self, angles): assert_allclose(res, ref) @pytest.mark.parametrize("lengths", comb_wr([-1, 0, 1, 2], 3)) - @pytest.mark.parametrize( - "angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3) - ) + @pytest.mark.parametrize("angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3)) def test_triclinic_box(self, lengths, angles): tri_vecs = self.ref_trivecs_unsafe(lengths + angles) ref = self.ref_tribox(tri_vecs) @@ -497,9 +487,7 @@ def test_triclinic_box(self, lengths, angles): assert res.dtype == ref.dtype @pytest.mark.parametrize("lengths", comb_wr([-1, 0, 1, 2], 3)) - @pytest.mark.parametrize( - "angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3) - ) + @pytest.mark.parametrize("angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3)) def test_box_volume(self, lengths, angles): box = np.array(lengths + angles, dtype=np.float32) assert_almost_equal( @@ -777,15 +765,11 @@ def test_make_whole_fullerene(self): blengths = u.atoms.bonds.values() # kaboom u.atoms[::2].translate([u.dimensions[0], -2 * u.dimensions[1], 0.0]) - u.atoms[1::2].translate( - [0.0, 7 * u.dimensions[1], -5 * u.dimensions[2]] - ) + u.atoms[1::2].translate([0.0, 7 * u.dimensions[1], -5 * u.dimensions[2]]) mdamath.make_whole(u.atoms) - assert_array_almost_equal( - u.atoms.bonds.values(), blengths, decimal=self.prec - ) + assert_array_almost_equal(u.atoms.bonds.values(), blengths, decimal=self.prec) def test_make_whole_multiple_molecules(self): u = mda.Universe(two_water_gro, guess_bonds=True) @@ -1307,9 +1291,7 @@ def test_get_parser(self, extention, parser): ], ) @pytest.mark.parametrize("compression_extention", compressed_extensions) - def test_get_parser_compressed( - self, extention, parser, compression_extention - ): + def test_get_parser_compressed(self, extention, parser, compression_extention): file_name = "file.{0}{1}".format(extention, compression_extention) a = mda.topology.core.get_parser_for(file_name) @@ -1351,9 +1333,7 @@ def test_get_reader(self, extention, reader): ], ) @pytest.mark.parametrize("compression_extention", compressed_extensions) - def test_get_reader_compressed( - self, extention, reader, compression_extention - ): + def test_get_reader_compressed(self, extention, reader, compression_extention): file_name = "file.{0}{1}".format(extention, compression_extention) a = mda.coordinates.core.get_reader_for(file_name) @@ -1396,16 +1376,12 @@ class TestUniqueRows(object): def test_unique_rows_2(self): a = np.array([[0, 1], [1, 2], [2, 1], [0, 1], [0, 1], [2, 1]]) - assert_array_equal( - util.unique_rows(a), np.array([[0, 1], [1, 2], [2, 1]]) - ) + assert_array_equal(util.unique_rows(a), np.array([[0, 1], [1, 2], [2, 1]])) def test_unique_rows_3(self): a = np.array([[0, 1, 2], [0, 1, 2], [2, 3, 4], [0, 1, 2]]) - assert_array_equal( - util.unique_rows(a), np.array([[0, 1, 2], [2, 3, 4]]) - ) + assert_array_equal(util.unique_rows(a), np.array([[0, 1, 2], [2, 3, 4]])) def test_unique_rows_with_view(self): # unique_rows doesn't work when flags['OWNDATA'] is False, @@ -1451,9 +1427,7 @@ def test_file_no_extension(self): def test_wrong_format(self): # Make sure ``get_writer_for`` fails if the format is unknown with pytest.raises(TypeError): - mda.coordinates.core.get_writer_for( - filename="fail_me", format="UNK" - ) + mda.coordinates.core.get_writer_for(filename="fail_me", format="UNK") def test_compressed_extension(self): for ext in (".gz", ".bz2"): @@ -1472,9 +1446,7 @@ def test_compressed_extension_fail(self): def test_non_string_filename(self): # Does ``get_writer_for`` fails with non string filename, no format with pytest.raises(ValueError): - mda.coordinates.core.get_writer_for( - filename=StringIO(), format=None - ) + mda.coordinates.core.get_writer_for(filename=StringIO(), format=None) def test_multiframe_failure(self): # does ``get_writer_for`` fail with invalid format and multiframe not None @@ -1522,9 +1494,7 @@ def test_multiframe_nonsense(self): ) def test_singleframe(self, format, writer): assert ( - mda.coordinates.core.get_writer_for( - "this", format=format, multiframe=False - ) + mda.coordinates.core.get_writer_for("this", format=format, multiframe=False) == writer ) @@ -1538,9 +1508,7 @@ def test_singleframe(self, format, writer): ) def test_singleframe_fails(self, format): with pytest.raises(TypeError): - mda.coordinates.core.get_writer_for( - "this", format=format, multiframe=False - ) + mda.coordinates.core.get_writer_for("this", format=format, multiframe=False) @pytest.mark.parametrize( "format, writer", @@ -1552,49 +1520,33 @@ def test_singleframe_fails(self, format): ) def test_multiframe(self, format, writer): assert ( - mda.coordinates.core.get_writer_for( - "this", format=format, multiframe=True - ) + mda.coordinates.core.get_writer_for("this", format=format, multiframe=True) == writer ) @pytest.mark.parametrize( "format", - [ - format_tuple[0] - for format_tuple in formats - if format_tuple[3] is False - ], + [format_tuple[0] for format_tuple in formats if format_tuple[3] is False], ) def test_multiframe_fails(self, format): with pytest.raises(TypeError): - mda.coordinates.core.get_writer_for( - "this", format=format, multiframe=True - ) + mda.coordinates.core.get_writer_for("this", format=format, multiframe=True) def test_get_writer_for_pdb(self): assert ( - mda.coordinates.core.get_writer_for( - "this", format="PDB", multiframe=False - ) + mda.coordinates.core.get_writer_for("this", format="PDB", multiframe=False) == mda.coordinates.PDB.PDBWriter ) assert ( - mda.coordinates.core.get_writer_for( - "this", format="PDB", multiframe=True - ) + mda.coordinates.core.get_writer_for("this", format="PDB", multiframe=True) == mda.coordinates.PDB.MultiPDBWriter ) assert ( - mda.coordinates.core.get_writer_for( - "this", format="ENT", multiframe=False - ) + mda.coordinates.core.get_writer_for("this", format="ENT", multiframe=False) == mda.coordinates.PDB.PDBWriter ) assert ( - mda.coordinates.core.get_writer_for( - "this", format="ENT", multiframe=True - ) + mda.coordinates.core.get_writer_for("this", format="ENT", multiframe=True) == mda.coordinates.PDB.MultiPDBWriter ) @@ -1606,9 +1558,7 @@ def test_blocks_of_1(self): view = util.blocks_of(arr, 1, 1) assert view.shape == (4, 1, 1) - assert_array_almost_equal( - view, np.array([[[0]], [[5]], [[10]], [[15]]]) - ) + assert_array_almost_equal(view, np.array([[[0]], [[5]], [[10]], [[15]]])) # Change my view, check changes are reflected in arr view[:] = 1001 @@ -1831,14 +1781,11 @@ class TestWarnIfNotUnique(object): """Tests concerning the decorator @warn_if_not_unique""" def warn_msg(self, func, group, group_name): - msg = ( - "{}.{}(): {} {} contains duplicates. Results might be " - "biased!".format( - group.__class__.__name__, - func.__name__, - group_name, - group.__repr__(), - ) + msg = "{}.{}(): {} {} contains duplicates. Results might be " "biased!".format( + group.__class__.__name__, + func.__name__, + group_name, + group.__repr__(), ) return msg @@ -2211,9 +2158,7 @@ def test_atomgroup_mismatched_lengths(self): ag1 = u.select_atoms("index 0 to 10") ag2 = u.atoms - @check_coords( - "ag1", "ag2", check_lengths_match=True, allow_atomgroup=True - ) + @check_coords("ag1", "ag2", check_lengths_match=True, allow_atomgroup=True) def func(ag1, ag2): return ag1, ag2 @@ -2243,21 +2188,16 @@ def func(a): with pytest.raises(TypeError) as err: func(a_inv_type) assert err.msg == ( - "func(): Parameter 'a' must be a numpy.ndarray, " - "got ." + "func(): Parameter 'a' must be a numpy.ndarray, " "got ." ) with pytest.raises(ValueError) as err: func(a_inv_shape_1d) - assert err.msg == ( - "func(): a.shape must be (3,) or (n, 3), got " "(6,)." - ) + assert err.msg == ("func(): a.shape must be (3,) or (n, 3), got " "(6,).") with pytest.raises(ValueError) as err: func(a_inv_shape_2d) - assert err.msg == ( - "func(): a.shape must be (3,) or (n, 3), got " "(3, 2)." - ) + assert err.msg == ("func(): a.shape must be (3,) or (n, 3), got " "(3, 2).") def test_usage_with_kwargs(self): @@ -2419,9 +2359,7 @@ def AlternateUniverse(anything): assert re.search(deprecation_line_2, doc) if remove: - deprecation_line_3 = "`{0}` will be removed in release {1}".format( - name, remove - ) + deprecation_line_3 = "`{0}` will be removed in release {1}".format(name, remove) assert re.search(deprecation_line_3, doc) # check that the old docs are still present @@ -2475,9 +2413,7 @@ class TestCheckBox(object): np.array(["1", "1", 1, 90, "90", "90"]), np.array([1, 1, 1, 90, 90, 90], dtype=np.float32), np.array([1, 1, 1, 90, 90, 90], dtype=np.float64), - np.array( - [1, 1, 1, 1, 1, 1, 90, 90, 90, 90, 90, 90], dtype=np.float32 - )[::2], + np.array([1, 1, 1, 1, 1, 1, 90, 90, 90, 90, 90, 90], dtype=np.float32)[::2], ), ) def test_check_box_ortho(self, box): @@ -2501,9 +2437,7 @@ def test_check_box_None(self): np.array(["1", "1", 2, 45, "90", "90"]), np.array([1, 1, 2, 45, 90, 90], dtype=np.float32), np.array([1, 1, 2, 45, 90, 90], dtype=np.float64), - np.array( - [1, 1, 1, 1, 2, 2, 45, 45, 90, 90, 90, 90], dtype=np.float32 - )[::2], + np.array([1, 1, 1, 1, 2, 2, 45, 45, 90, 90, 90, 90], dtype=np.float32)[::2], ), ) def test_check_box_tri_vecs(self, box): diff --git a/testsuite/MDAnalysisTests/test_api.py b/testsuite/MDAnalysisTests/test_api.py index 2819cd549a..be46d34b5d 100644 --- a/testsuite/MDAnalysisTests/test_api.py +++ b/testsuite/MDAnalysisTests/test_api.py @@ -75,8 +75,7 @@ def test_all_import(submodule): name for name in module.__all__ if name not in module.__dict__.keys() - and name - not in [os.path.splitext(f)[0] for f in os.listdir(module_path)] + and name not in [os.path.splitext(f)[0] for f in os.listdir(module_path)] ] assert_equal( missing, diff --git a/testsuite/MDAnalysisTests/topology/base.py b/testsuite/MDAnalysisTests/topology/base.py index e7649d65f8..7aa48d3d07 100644 --- a/testsuite/MDAnalysisTests/topology/base.py +++ b/testsuite/MDAnalysisTests/topology/base.py @@ -57,16 +57,12 @@ def test_mandatory_attributes(self, top): # attributes required as part of the API # ALL parsers must provide these for attr in mandatory_attrs: - assert hasattr(top, attr), "Missing required attribute: {}".format( - attr - ) + assert hasattr(top, attr), "Missing required attribute: {}".format(attr) def test_expected_attributes(self, top): # Extra attributes as declared in specific implementations for attr in self.expected_attrs: - assert hasattr(top, attr), "Missing expected attribute: {}".format( - attr - ) + assert hasattr(top, attr), "Missing expected attribute: {}".format(attr) def test_no_unexpected_attributes(self, top): attrs = set( @@ -117,9 +113,7 @@ def test_guessed_attributes(self, filename): """check that the universe created with certain parser have the same guessed attributes as when it was guessed inside the parser""" u = mda.Universe(filename) - u_guessed_attrs = [ - attr.attrname for attr in u._topology.guessed_attributes - ] + u_guessed_attrs = [attr.attrname for attr in u._topology.guessed_attributes] for attr in self.guessed_attrs: assert hasattr(u.atoms, attr) assert attr in u_guessed_attrs diff --git a/testsuite/MDAnalysisTests/topology/test_fhiaims.py b/testsuite/MDAnalysisTests/topology/test_fhiaims.py index 4086c107df..c7c46486f2 100644 --- a/testsuite/MDAnalysisTests/topology/test_fhiaims.py +++ b/testsuite/MDAnalysisTests/topology/test_fhiaims.py @@ -46,9 +46,7 @@ def test_guessed_types(self, filename): def test_guessed_masses(self, filename): u = mda.Universe(filename) - assert_allclose( - u.atoms.masses, [15.999, 1.008, 1.008, 15.999, 1.008, 1.008] - ) + assert_allclose(u.atoms.masses, [15.999, 1.008, 1.008, 15.999, 1.008, 1.008]) def test_elements(self, top): assert_equal(top.elements.values, ["O", "H", "H", "O", "H", "H"]) diff --git a/testsuite/MDAnalysisTests/topology/test_gms.py b/testsuite/MDAnalysisTests/topology/test_gms.py index 8becdfda6f..1597ec2e95 100644 --- a/testsuite/MDAnalysisTests/topology/test_gms.py +++ b/testsuite/MDAnalysisTests/topology/test_gms.py @@ -66,9 +66,7 @@ class TestGMSSYMOPT(GMSBase): ref_filename = GMS_SYMOPT def test_names(self, top): - assert_equal( - top.names.values, ["CARBON", "CARBON", "HYDROGEN", "HYDROGEN"] - ) + assert_equal(top.names.values, ["CARBON", "CARBON", "HYDROGEN", "HYDROGEN"]) def test_types(self, top): assert_equal(top.atomiccharges.values, [6, 6, 1, 1]) diff --git a/testsuite/MDAnalysisTests/topology/test_guessers.py b/testsuite/MDAnalysisTests/topology/test_guessers.py index 69b1046f82..2f6004e4b5 100644 --- a/testsuite/MDAnalysisTests/topology/test_guessers.py +++ b/testsuite/MDAnalysisTests/topology/test_guessers.py @@ -160,9 +160,7 @@ def bond_sort(arr): def test_guess_bonds_water(): u = mda.Universe(datafiles.two_water_gro) - bonds = bond_sort( - guessers.guess_bonds(u.atoms, u.atoms.positions, u.dimensions) - ) + bonds = bond_sort(guessers.guess_bonds(u.atoms, u.atoms.positions, u.dimensions)) assert_equal(bonds, ((0, 1), (0, 2), (3, 4), (3, 5))) diff --git a/testsuite/MDAnalysisTests/topology/test_itp.py b/testsuite/MDAnalysisTests/topology/test_itp.py index 5b3cf93411..6d305b549d 100644 --- a/testsuite/MDAnalysisTests/topology/test_itp.py +++ b/testsuite/MDAnalysisTests/topology/test_itp.py @@ -367,9 +367,7 @@ def test_defines(self, top): def test_guessed_masses(self, filename): u = mda.Universe(filename) - assert_allclose( - u.atoms.masses, [15.999, 15.999, 15.999, 15.999, 15.999] - ) + assert_allclose(u.atoms.masses, [15.999, 15.999, 15.999, 15.999, 15.999]) class TestITPKeywords(TestITPNoKeywords): @@ -394,9 +392,7 @@ def universe(self, filename): @pytest.fixture() def top(self, filename): with self.parser(filename) as p: - yield p.parse( - FLEXIBLE=True, EXTRA_ATOMS=True, HW1_CHARGE=1, HW2_CHARGE=3 - ) + yield p.parse(FLEXIBLE=True, EXTRA_ATOMS=True, HW1_CHARGE=1, HW2_CHARGE=3) def test_whether_settles_types(self, universe): for param in list(universe.bonds) + list(universe.angles): @@ -429,9 +425,7 @@ class TestNestedIfs(BaseITP): @pytest.fixture def universe(self, filename): - return mda.Universe( - filename, HEAVY_H=True, EXTRA_ATOMS=True, HEAVY_SIX=True - ) + return mda.Universe(filename, HEAVY_H=True, EXTRA_ATOMS=True, HEAVY_SIX=True) @pytest.fixture() def top(self, filename): @@ -465,9 +459,7 @@ def top(self, filename): @pytest.fixture() def universe(self, filename): - return mda.Universe( - filename, topology_format="ITP", include_dir=GMX_DIR - ) + return mda.Universe(filename, topology_format="ITP", include_dir=GMX_DIR) def test_output(self, filename): """Testing the call signature""" @@ -488,9 +480,7 @@ def test_guessed_attributes(self, filename): def test_sequential(self, universe): resids = np.array(list(range(2, 12)) + list(range(13, 23))) assert_equal(universe.residues.resids[:20], resids) - assert_equal( - universe.residues.resindices, np.arange(self.expected_n_residues) - ) + assert_equal(universe.residues.resindices, np.arange(self.expected_n_residues)) assert_equal(universe.atoms.chargegroups[-1], 63) diff --git a/testsuite/MDAnalysisTests/topology/test_lammpsdata.py b/testsuite/MDAnalysisTests/topology/test_lammpsdata.py index d384941237..96c40eefab 100644 --- a/testsuite/MDAnalysisTests/topology/test_lammpsdata.py +++ b/testsuite/MDAnalysisTests/topology/test_lammpsdata.py @@ -300,9 +300,7 @@ def test_interpret_atom_style(): def test_interpret_atom_style_missing(): - with pytest.raises( - ValueError, match="atom_style string missing required.+?" - ): + with pytest.raises(ValueError, match="atom_style string missing required.+?"): style = mda.topology.LAMMPSParser.DATAParser._interpret_atom_style( "id charge z y x" ) diff --git a/testsuite/MDAnalysisTests/topology/test_minimal.py b/testsuite/MDAnalysisTests/topology/test_minimal.py index 2d0e1ffd87..761d1c91bc 100644 --- a/testsuite/MDAnalysisTests/topology/test_minimal.py +++ b/testsuite/MDAnalysisTests/topology/test_minimal.py @@ -104,9 +104,7 @@ def memory_possibilities(): yield array, order -memory_reader = pytest.mark.parametrize( - "array,order", list(memory_possibilities()) -) +memory_reader = pytest.mark.parametrize("array,order", list(memory_possibilities())) @memory_reader diff --git a/testsuite/MDAnalysisTests/topology/test_mol2.py b/testsuite/MDAnalysisTests/topology/test_mol2.py index 4157e8273a..ad588302ff 100644 --- a/testsuite/MDAnalysisTests/topology/test_mol2.py +++ b/testsuite/MDAnalysisTests/topology/test_mol2.py @@ -224,9 +224,7 @@ def test_bond_orders(): def test_elements(): u = mda.Universe(mol2_molecule) - assert_equal( - u.atoms.elements[:5], np.array(["N", "S", "N", "N", "O"], dtype="U3") - ) + assert_equal(u.atoms.elements[:5], np.array(["N", "S", "N", "N", "O"], dtype="U3")) # Test for #2927 @@ -305,9 +303,7 @@ def test_partial_optional_columns(): def test_mol2_wo_required_columns(): - with pytest.raises( - ValueError, match="The @ATOM block in mol2 file" - ): + with pytest.raises(ValueError, match="The @ATOM block in mol2 file"): u = mda.Universe(StringIO(mol2_wo_required_col), format="MOL2") diff --git a/testsuite/MDAnalysisTests/topology/test_pdb.py b/testsuite/MDAnalysisTests/topology/test_pdb.py index 736e0f25f3..ab740939bb 100644 --- a/testsuite/MDAnalysisTests/topology/test_pdb.py +++ b/testsuite/MDAnalysisTests/topology/test_pdb.py @@ -302,10 +302,7 @@ def test_missing_elements_noattribute(): 1) a warning is raised if elements are missing 2) the elements attribute is not set """ - wmsg = ( - "Element information is missing, elements attribute will not be " - "populated" - ) + wmsg = "Element information is missing, elements attribute will not be " "populated" with pytest.warns(UserWarning, match=wmsg): u = mda.Universe(PDB_small) with pytest.raises(AttributeError): diff --git a/testsuite/MDAnalysisTests/topology/test_pqr.py b/testsuite/MDAnalysisTests/topology/test_pqr.py index df3790b7a7..5efffff96c 100644 --- a/testsuite/MDAnalysisTests/topology/test_pqr.py +++ b/testsuite/MDAnalysisTests/topology/test_pqr.py @@ -113,6 +113,4 @@ def test_gromacs_flavour(): assert_almost_equal(u.atoms[0].radius, 1.48, decimal=5) assert_almost_equal(u.atoms[0].charge, -0.67, decimal=5) # coordinatey things - assert_almost_equal( - u.atoms[0].position, [15.710, 17.670, 23.340], decimal=4 - ) + assert_almost_equal(u.atoms[0].position, [15.710, 17.670, 23.340], decimal=4) diff --git a/testsuite/MDAnalysisTests/topology/test_top.py b/testsuite/MDAnalysisTests/topology/test_top.py index a67c9283b7..653ace458b 100644 --- a/testsuite/MDAnalysisTests/topology/test_top.py +++ b/testsuite/MDAnalysisTests/topology/test_top.py @@ -90,18 +90,12 @@ def test_angles_atom_counts(self, filename): def test_dihedrals_atom_counts(self, filename): u = mda.Universe(filename) assert len(u.atoms[[0]].dihedrals) == self.expected_n_zero_dihedrals - assert ( - len(u.atoms[[self.atom_i]].dihedrals) - == self.expected_n_i_dihedrals - ) + assert len(u.atoms[[self.atom_i]].dihedrals) == self.expected_n_i_dihedrals def test_impropers_atom_counts(self, filename): u = mda.Universe(filename) assert len(u.atoms[[0]].impropers) == self.expected_n_zero_impropers - assert ( - len(u.atoms[[self.atom_i]].impropers) - == self.expected_n_i_impropers - ) + assert len(u.atoms[[self.atom_i]].impropers) == self.expected_n_i_impropers def test_bonds_identity(self, top): vals = top.bonds.values @@ -150,10 +144,7 @@ def test_improper_atoms_bonded(self, top): backward = ((imp[0], imp[1]), (imp[1], imp[2]), (imp[1], imp[3])) for a, b in zip(forward, backward): assert ( - (b in vals) - or (b[::-1] in vals) - or (a in vals) - or (a[::-1] in vals) + (b in vals) or (b[::-1] in vals) or (a in vals) or (a[::-1] in vals) ) def test_elements(self, top): @@ -403,9 +394,7 @@ def test_chainIDs(self, filename): u = mda.Universe(filename) if hasattr(self, "expected_chainIDs"): - reschainIDs = [ - atomchainIDs[0] for atomchainIDs in u.residues.chainIDs - ] + reschainIDs = [atomchainIDs[0] for atomchainIDs in u.residues.chainIDs] assert_equal( reschainIDs, self.expected_chainIDs, "unexpected element match" ) @@ -790,7 +779,9 @@ class TestPRMEP(TOPBase): class TestErrorsAndWarnings(object): - ATOMIC_NUMBER_MSG = "ATOMIC_NUMBER record not found, elements attribute will not be populated" + ATOMIC_NUMBER_MSG = ( + "ATOMIC_NUMBER record not found, elements attribute will not be populated" + ) MISSING_ELEM_MSG = ( "Unknown ATOMIC_NUMBER value found for some atoms, " "these have been given an empty element record" diff --git a/testsuite/MDAnalysisTests/topology/test_topology_base.py b/testsuite/MDAnalysisTests/topology/test_topology_base.py index 33d03258f9..16a7842e15 100644 --- a/testsuite/MDAnalysisTests/topology/test_topology_base.py +++ b/testsuite/MDAnalysisTests/topology/test_topology_base.py @@ -6,9 +6,7 @@ class TestSquash(object): atom_resids = np.array([2, 2, 1, 1, 5, 5, 4, 4]) - atom_resnames = np.array( - ["A", "A", "B", "B", "C", "C", "D", "D"], dtype=object - ) + atom_resnames = np.array(["A", "A", "B", "B", "C", "C", "D", "D"], dtype=object) def test_squash(self): atom_residx, resids, (resnames,) = squash_by( diff --git a/testsuite/MDAnalysisTests/topology/test_tprparser.py b/testsuite/MDAnalysisTests/topology/test_tprparser.py index b8ec5425d1..f8dc791144 100644 --- a/testsuite/MDAnalysisTests/topology/test_tprparser.py +++ b/testsuite/MDAnalysisTests/topology/test_tprparser.py @@ -114,9 +114,7 @@ def test_molnums(self, top): def test_chainIDs(self, top): if hasattr(self, "ref_chainIDs"): - assert_equal( - self.ref_chainIDs, getattr(top, "chainIDs").name_lookup - ) + assert_equal(self.ref_chainIDs, getattr(top, "chainIDs").name_lookup) class TestTPR(TPRAttrs): @@ -343,9 +341,7 @@ def bonds_water(request): # The index of the first water atom is 1960 first = 1960 bonds = [ - bond - for bond in parser.bonds.values - if bond[0] >= first and bond[1] >= first + bond for bond in parser.bonds.values if bond[0] >= first and bond[1] >= first ] return bonds diff --git a/testsuite/MDAnalysisTests/topology/test_txyz.py b/testsuite/MDAnalysisTests/topology/test_txyz.py index 5615bdc985..307beb7cb2 100644 --- a/testsuite/MDAnalysisTests/topology/test_txyz.py +++ b/testsuite/MDAnalysisTests/topology/test_txyz.py @@ -61,9 +61,7 @@ def test_TXYZ_elements(): properly given a TXYZ file with valid elements record. """ u = mda.Universe(TXYZ, format="TXYZ") - element_list = np.array( - ["C", "H", "H", "O", "H", "C", "H", "H", "H"], dtype=object - ) + element_list = np.array(["C", "H", "H", "O", "H", "C", "H", "H", "H"], dtype=object) assert_equal(u.atoms.elements, element_list) diff --git a/testsuite/MDAnalysisTests/transformations/test_base.py b/testsuite/MDAnalysisTests/transformations/test_base.py index 492c2825b4..feb00838c5 100644 --- a/testsuite/MDAnalysisTests/transformations/test_base.py +++ b/testsuite/MDAnalysisTests/transformations/test_base.py @@ -52,9 +52,7 @@ 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() diff --git a/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py b/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py index a1d88b7840..06989267ed 100644 --- a/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py +++ b/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py @@ -51,9 +51,7 @@ 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 - ) + assert_array_almost_equal(boxdimensions_universe.dimensions, new_dims, decimal=6) @pytest.mark.parametrize( @@ -83,9 +81,7 @@ def test_dimensions_vector(boxdimensions_universe, dim_vector_shapes): "abcd", ), ) -def test_dimensions_vector_asarray( - boxdimensions_universe, dim_vector_forms_dtypes -): +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"): @@ -142,9 +138,5 @@ def test_varying_dimensions_no_data( ] ) 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 ecd4a87dd7..e74d9f6676 100644 --- a/testsuite/MDAnalysisTests/transformations/test_fit.py +++ b/testsuite/MDAnalysisTests/transformations/test_fit.py @@ -155,9 +155,7 @@ 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 diff --git a/testsuite/MDAnalysisTests/transformations/test_nojump.py b/testsuite/MDAnalysisTests/transformations/test_nojump.py index f295ec33a7..a6f9e56ac1 100644 --- a/testsuite/MDAnalysisTests/transformations/test_nojump.py +++ b/testsuite/MDAnalysisTests/transformations/test_nojump.py @@ -125,12 +125,8 @@ def nojump_universe_npt_2nd_frame_from_file(tmp_path_factory): 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: @@ -203,9 +199,7 @@ 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 = [ @@ -303,9 +297,7 @@ 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): diff --git a/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py b/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py index f3ae050f6b..0fbda82741 100644 --- a/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py +++ b/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py @@ -101,9 +101,7 @@ def test_posavging_specific(posaveraging_universes): for ts in posaveraging_universes.trajectory[fr_list]: np.copyto(specr_avgd[..., idx], ts.positions) 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): @@ -124,6 +122,4 @@ def test_posavging_specific_noreset(posaveraging_universes_noreset): for ts in posaveraging_universes_noreset.trajectory[fr_list]: np.copyto(specr_avgd[..., idx], ts.positions) 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 4f8fd9867b..db2220fa4c 100644 --- a/testsuite/MDAnalysisTests/transformations/test_rotate.py +++ b/testsuite/MDAnalysisTests/transformations/test_rotate.py @@ -36,9 +36,7 @@ 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.0, 373.0, 374.0, 90, 90, 90] - ) + transformed.trajectory.ts.dimensions = np.array([372.0, 373.0, 374.0, 90, 90, 90]) return reference, transformed @@ -74,9 +72,7 @@ def test_rotation_matrix(): 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? ref_u = rotate_universes[0] @@ -92,9 +88,7 @@ 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? ref_u = rotate_universes[0] @@ -157,9 +151,7 @@ def test_rotateby_atomgroup_cog_pbc(rotate_universes): 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) @@ -176,9 +168,9 @@ def test_rotateby_atomgroup_com_pbc(rotate_universes): 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) diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index ccb431f3c5..3961d88dff 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -36,9 +36,7 @@ def translate_universes(): # 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.0, 373.0, 374.0, 90, 90, 90] - ) + transformed.trajectory.ts.dimensions = np.array([372.0, 373.0, 374.0, 90, 90, 90]) return reference, transformed @@ -78,9 +76,7 @@ def test_translate_transformations_api(translate_universes): 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): @@ -219,6 +215,4 @@ def test_center_transformations_api(translate_universes): 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 a3439fb95c..a35b03644c 100644 --- a/testsuite/MDAnalysisTests/transformations/test_wrap.py +++ b/testsuite/MDAnalysisTests/transformations/test_wrap.py @@ -93,15 +93,11 @@ def test_wrap_no_options(wrap_universes): ) -@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 ref.select_atoms("not resname SOL").wrap(compound=compound) - wrap(trans.select_atoms("not resname SOL"), compound=compound)( - trans.trajectory.ts - ) + 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 ) diff --git a/testsuite/MDAnalysisTests/util.py b/testsuite/MDAnalysisTests/util.py index 58cec2cbac..27c4daef53 100644 --- a/testsuite/MDAnalysisTests/util.py +++ b/testsuite/MDAnalysisTests/util.py @@ -254,13 +254,10 @@ def __exit__(self, exc_type, exc_val, exc_tb): PendingDeprecationWarning, ) if any( - issubclass(c, deprecation_categories) - for c in self._captured_categories + issubclass(c, deprecation_categories) for c in self._captured_categories ): __tracebackhide__ = True - msg = ( - "Produced DeprecationWarning or PendingDeprecationWarning" - ) + msg = "Produced DeprecationWarning or PendingDeprecationWarning" raise AssertionError(msg) diff --git a/testsuite/MDAnalysisTests/utils/test_authors.py b/testsuite/MDAnalysisTests/utils/test_authors.py index 13563dadfd..eff77586d5 100644 --- a/testsuite/MDAnalysisTests/utils/test_authors.py +++ b/testsuite/MDAnalysisTests/utils/test_authors.py @@ -26,6 +26,4 @@ def test_package_authors(): - assert ( - len(MDAnalysis.__authors__) > 0 - ), "Could not find the list of authors" + assert len(MDAnalysis.__authors__) > 0, "Could not find the list of authors" diff --git a/testsuite/MDAnalysisTests/utils/test_duecredit.py b/testsuite/MDAnalysisTests/utils/test_duecredit.py index c99f14dbf9..fe07d6d1b0 100644 --- a/testsuite/MDAnalysisTests/utils/test_duecredit.py +++ b/testsuite/MDAnalysisTests/utils/test_duecredit.py @@ -40,10 +40,7 @@ @pytest.mark.skipif( - ( - os.environ.get("DUECREDIT_ENABLE", "yes").lower() - in ("no", "0", "false") - ), + (os.environ.get("DUECREDIT_ENABLE", "yes").lower() in ("no", "0", "false")), reason="duecredit is explicitly disabled with DUECREDIT_ENABLE=no", ) class TestDuecredit(object): diff --git a/testsuite/MDAnalysisTests/utils/test_failure.py b/testsuite/MDAnalysisTests/utils/test_failure.py index 494e84cdb9..29ff10b846 100644 --- a/testsuite/MDAnalysisTests/utils/test_failure.py +++ b/testsuite/MDAnalysisTests/utils/test_failure.py @@ -28,6 +28,4 @@ def test_failure(): if "MDA_FAILURE_TEST" in os.environ: # Have a file open to trigger an output from the open_files plugin. f = open("./failure.txt", "w") - raise AssertionError( - "the MDA_FAILURE_TEST environment variable is set" - ) + raise AssertionError("the MDA_FAILURE_TEST environment variable is set") diff --git a/testsuite/MDAnalysisTests/utils/test_imports.py b/testsuite/MDAnalysisTests/utils/test_imports.py index 016388e324..aefbf59fa0 100644 --- a/testsuite/MDAnalysisTests/utils/test_imports.py +++ b/testsuite/MDAnalysisTests/utils/test_imports.py @@ -61,7 +61,5 @@ def test_relative_import(testing_module): ): raise AssertionError( "A relative import statement was found in " - "module {testing_module} at linenumber {lineno}.".format( - **vars() - ) + "module {testing_module} at linenumber {lineno}.".format(**vars()) ) diff --git a/testsuite/MDAnalysisTests/utils/test_meta.py b/testsuite/MDAnalysisTests/utils/test_meta.py index b6e536ef00..a9790fe811 100644 --- a/testsuite/MDAnalysisTests/utils/test_meta.py +++ b/testsuite/MDAnalysisTests/utils/test_meta.py @@ -55,9 +55,7 @@ def test_version_format(version=None): r"(?P\d+)\.(?P\d+)\.(?P\d+)(-(?P\w+))?$", version, ) - assert ( - m - ), "version {0} does not match the MAJOR.MINOR.PATCH(-suffix) format".format( + assert m, "version {0} does not match the MAJOR.MINOR.PATCH(-suffix) format".format( version ) diff --git a/testsuite/MDAnalysisTests/utils/test_modelling.py b/testsuite/MDAnalysisTests/utils/test_modelling.py index c014c9f4d0..a316fa2a64 100644 --- a/testsuite/MDAnalysisTests/utils/test_modelling.py +++ b/testsuite/MDAnalysisTests/utils/test_modelling.py @@ -71,9 +71,7 @@ def capping(ref, ace, nma, output): "mobile": "resid {0} and backbone and not (resname NMA NME)".format( resid_max ), - "reference": "resid {0} and (backbone or name OT2)".format( - resid_max - ), + "reference": "resid {0} and (backbone or name OT2)".format(resid_max), }, strict=True, ) @@ -118,9 +116,7 @@ def test_capping_file(self, tmpdir): assert_equal(ace.resids[0], 1) assert_equal(nma.resids[0], 16) - assert_array_equal( - peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions - ) + assert_array_equal(peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions) def test_capping_inmemory(self, tmpdir): peptide = MDAnalysis.Universe(capping_input) @@ -142,9 +138,7 @@ def test_capping_inmemory(self, tmpdir): assert_equal(ace.resids[0], 1) assert_equal(nma.resids[0], 16) - assert_array_equal( - peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions - ) + assert_array_equal(peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions) @pytest.fixture() @@ -169,9 +163,7 @@ def u_without_coords(): class TestMerge(object): def test_merge(self, u_protein, u_ligand, u_water, tmpdir): - ids_before = [ - a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms - ] + ids_before = [a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms] # Do the merge u0 = MDAnalysis.Merge(u_protein.atoms, u_ligand.atoms, u_water.atoms) # Check that the output Universe has the same number of atoms as the @@ -184,19 +176,11 @@ def test_merge(self, u_protein, u_ligand, u_water, tmpdir): # segments as the starting AtomGroups assert_equal( len(u0.residues), - ( - len(u_protein.residues) - + len(u_ligand.residues) - + len(u_water.residues) - ), + (len(u_protein.residues) + len(u_ligand.residues) + len(u_water.residues)), ) assert_equal( len(u0.segments), - ( - len(u_protein.segments) - + len(u_ligand.segments) - + len(u_water.segments) - ), + (len(u_protein.segments) + len(u_ligand.segments) + len(u_water.segments)), ) # Make sure that all the atoms in the new universe are assigned to only @@ -208,9 +192,7 @@ def test_merge(self, u_protein, u_ligand, u_water, tmpdir): # Make sure that the atom ids of the original universes are unchanged, # ie we didn't make the original Universes 'dirty' - ids_after = [ - a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms - ] + ids_after = [a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms] assert_equal( len(ids_after), (len(u_protein.atoms) + len(u_ligand.atoms) + len(u_water.atoms)), @@ -229,9 +211,7 @@ def test_merge(self, u_protein, u_ligand, u_water, tmpdir): assert_equal(ids_new, ids_new2) def test_merge_same_universe(self, u_protein): - u0 = MDAnalysis.Merge( - u_protein.atoms, u_protein.atoms, u_protein.atoms - ) + u0 = MDAnalysis.Merge(u_protein.atoms, u_protein.atoms, u_protein.atoms) assert_equal(len(u0.atoms), 3 * len(u_protein.atoms)) assert_equal(len(u0.residues), 3 * len(u_protein.residues)) assert_equal(len(u0.segments), 3 * len(u_protein.segments)) @@ -307,18 +287,9 @@ def test_merge_with_topology_from_different_universes(self, u, u_ligand): # PDB reader yields empty Bonds group, which means bonds from # PSF/DCD survive the merge # assert(not hasattr(u_merge.atoms, 'bonds') or len(u_merge.atoms.bonds) == 0) - assert ( - not hasattr(u_merge.atoms, "angles") - or len(u_merge.atoms.bonds) == 0 - ) - assert ( - not hasattr(u_merge.atoms, "dihedrals") - or len(u_merge.atoms.bonds) == 0 - ) - assert ( - not hasattr(u_merge.atoms, "impropers") - or len(u_merge.atoms.bonds) == 0 - ) + assert not hasattr(u_merge.atoms, "angles") or len(u_merge.atoms.bonds) == 0 + assert not hasattr(u_merge.atoms, "dihedrals") or len(u_merge.atoms.bonds) == 0 + assert not hasattr(u_merge.atoms, "impropers") or len(u_merge.atoms.bonds) == 0 def test_merge_without_topology(self, u): # This shouldn't have topology as we merged single atoms diff --git a/testsuite/MDAnalysisTests/utils/test_pickleio.py b/testsuite/MDAnalysisTests/utils/test_pickleio.py index ae6c342cec..00c5b7307c 100644 --- a/testsuite/MDAnalysisTests/utils/test_pickleio.py +++ b/testsuite/MDAnalysisTests/utils/test_pickleio.py @@ -163,9 +163,7 @@ def test_pickle_with_write_mode(unpicklable_f, tmpdir): def test_GSD_pickle(): gsd_io = gsd_pickle_open(GSD, mode="r") gsd_io_pickled = pickle.loads(pickle.dumps(gsd_io)) - assert_equal( - gsd_io[0].particles.position, gsd_io_pickled[0].particles.position - ) + assert_equal(gsd_io[0].particles.position, gsd_io_pickled[0].particles.position) @pytest.mark.skipif(not HAS_GSD, reason="gsd not installed") @@ -189,9 +187,7 @@ def test_NCDF_mmap_pickle(): assert_equal(ncdf_io_pickled.use_mmap, False) -@pytest.mark.skipif( - not check_chemfiles_version(), reason="Wrong version of chemfiles" -) +@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") def test_Chemfiles_pickle(): chemfiles_io = ChemfilesPicklable(XYZ) chemfiles_io_pickled = pickle.loads(pickle.dumps(chemfiles_io)) @@ -202,14 +198,10 @@ def test_Chemfiles_pickle(): assert_equal(frame.positions[:], frame_pickled.positions[:]) -@pytest.mark.skipif( - not check_chemfiles_version(), reason="Wrong version of chemfiles" -) +@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") def test_Chemfiles_with_write_mode(tmpdir): with pytest.raises(ValueError, match=r"Only read mode"): - chemfiles_io = ChemfilesPicklable( - tmpdir.mkdir("xyz").join("t.xyz"), mode="w" - ) + chemfiles_io = ChemfilesPicklable(tmpdir.mkdir("xyz").join("t.xyz"), mode="w") @pytest.mark.skipif(not HAS_H5PY, reason="h5py not installed") diff --git a/testsuite/MDAnalysisTests/utils/test_qcprot.py b/testsuite/MDAnalysisTests/utils/test_qcprot.py index 8ee971c227..206ad73b55 100644 --- a/testsuite/MDAnalysisTests/utils/test_qcprot.py +++ b/testsuite/MDAnalysisTests/utils/test_qcprot.py @@ -47,9 +47,7 @@ @pytest.fixture() def atoms_a(): - return np.array( - [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], dtype=np.float64 - ) + return np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], dtype=np.float64) @pytest.fixture() diff --git a/testsuite/MDAnalysisTests/utils/test_selections.py b/testsuite/MDAnalysisTests/utils/test_selections.py index 212bce97da..4f31c50c12 100644 --- a/testsuite/MDAnalysisTests/utils/test_selections.py +++ b/testsuite/MDAnalysisTests/utils/test_selections.py @@ -42,9 +42,7 @@ class _SelectionWriter(object): filename = None - max_number = ( - 357 # to keep fixtures smallish, only select CAs up to number 357 - ) + max_number = 357 # to keep fixtures smallish, only select CAs up to number 357 @staticmethod @pytest.fixture() @@ -229,9 +227,7 @@ class TestSelectionWriter_Jmol(_SelectionWriter): def _assert_selectionstring(self, namedfile): header, indices = spt2array(namedfile.readline()) - assert_equal( - header, self.ref_name, err_msg="SPT file has wrong selection name" - ) + assert_equal(header, self.ref_name, err_msg="SPT file has wrong selection name") assert_array_equal( indices, self.ref_indices, diff --git a/testsuite/MDAnalysisTests/utils/test_streamio.py b/testsuite/MDAnalysisTests/utils/test_streamio.py index 56a421dda7..417ec78509 100644 --- a/testsuite/MDAnalysisTests/utils/test_streamio.py +++ b/testsuite/MDAnalysisTests/utils/test_streamio.py @@ -229,9 +229,7 @@ def test_join(self, tmpdir, funcname="join"): ) def test_expanduser_noexpansion_returns_NamedStream(self): - ns = self.create_NamedStream( - "de/zipferlack.txt" - ) # no tilde ~ in name! + ns = self.create_NamedStream("de/zipferlack.txt") # no tilde ~ in name! reference = ns.name value = os.path.expanduser(ns) assert_equal( @@ -448,9 +446,7 @@ def test_MOL2Reader(self, streamData): assert_equal(len(u.atoms), 49) assert_equal(u.trajectory.n_frames, 200) u.trajectory[199] - assert_array_almost_equal( - u.atoms.positions[0], [1.7240, 11.2730, 14.1200] - ) + assert_array_almost_equal(u.atoms.positions[0], [1.7240, 11.2730, 14.1200]) def test_XYZReader(self, streamData): u = MDAnalysis.Universe( @@ -459,9 +455,7 @@ def test_XYZReader(self, streamData): ) assert_equal(len(u.atoms), 8) assert_equal(u.trajectory.n_frames, 3) - assert_equal( - u.trajectory.frame, 0 - ) # weird, something odd with XYZ reader + assert_equal(u.trajectory.frame, 0) # weird, something odd with XYZ reader u.trajectory.next() # (should really only need one next()... ) assert_equal(u.trajectory.frame, 1) # !!!! ??? u.trajectory.next() # frame 2 diff --git a/testsuite/MDAnalysisTests/utils/test_transformations.py b/testsuite/MDAnalysisTests/utils/test_transformations.py index 72d6831cd1..d6a0795b89 100644 --- a/testsuite/MDAnalysisTests/utils/test_transformations.py +++ b/testsuite/MDAnalysisTests/utils/test_transformations.py @@ -230,9 +230,7 @@ def test_projection_from_matrix_2(self, data): def test_projection_from_matrix_3(self, data): point, normal, direct, persp = data - P0 = t.projection_matrix( - point, normal, perspective=persp, pseudo=False - ) + P0 = t.projection_matrix(point, normal, perspective=persp, pseudo=False) result = t.projection_from_matrix(P0, pseudo=False) P1 = t.projection_matrix(*result) assert_equal(t.is_same_transform(P0, P1), True) @@ -537,9 +535,7 @@ def test_quaternion_from_matrix_2(self, f): def test_quaternion_from_matrix_3(self, f): R = t.rotation_matrix(0.123, (1, 2, 3)) q = f(R, True) - assert_allclose( - q, [0.9981095, 0.0164262, 0.0328524, 0.0492786], atol=_ATOL - ) + assert_allclose(q, [0.9981095, 0.0164262, 0.0328524, 0.0492786], atol=_ATOL) def test_quaternion_from_matrix_4(self, f): R = [ diff --git a/testsuite/MDAnalysisTests/utils/test_units.py b/testsuite/MDAnalysisTests/utils/test_units.py index 8121188c1c..31f41b0352 100644 --- a/testsuite/MDAnalysisTests/utils/test_units.py +++ b/testsuite/MDAnalysisTests/utils/test_units.py @@ -39,9 +39,7 @@ def test_unicode_encoding_with_symbol(self): try: assert_equal(units.lengthUnit_factor["Å"], 1.0) except KeyError: - raise AssertionError( - "UTF-8-encoded symbol for Angtrom not supported" - ) + raise AssertionError("UTF-8-encoded symbol for Angtrom not supported") class TestConstants(object): diff --git a/testsuite/MDAnalysisTests/visualization/test_streamlines.py b/testsuite/MDAnalysisTests/visualization/test_streamlines.py index 80bd4299cf..6902bed671 100644 --- a/testsuite/MDAnalysisTests/visualization/test_streamlines.py +++ b/testsuite/MDAnalysisTests/visualization/test_streamlines.py @@ -172,9 +172,7 @@ def test_per_core_work_2D(membrane_xtc, univ): ymin = univ.atoms.positions[..., 1].min() ymax = univ.atoms.positions[..., 1].max() tuple_of_limits = (xmin, xmax, ymin, ymax) - grid = streamlines.produce_grid( - tuple_of_limits=tuple_of_limits, grid_spacing=20 - ) + grid = streamlines.produce_grid(tuple_of_limits=tuple_of_limits, grid_spacing=20) ( list_square_vertex_arrays_per_core, list_parent_index_values, @@ -184,9 +182,7 @@ def test_per_core_work_2D(membrane_xtc, univ): values = streamlines.per_core_work( topology_file_path=Martini_membrane_gro, trajectory_file_path=membrane_xtc, - list_square_vertex_arrays_this_core=list_square_vertex_arrays_per_core[ - 0 - ], + list_square_vertex_arrays_this_core=list_square_vertex_arrays_per_core[0], MDA_selection="name PO4", start_frame=1, end_frame=2, From 7ad3e09d490b2f86f2e36084b5c5f59d49473281 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Tue, 22 Jul 2025 18:17:47 -0400 Subject: [PATCH 09/26] Revert "ran black 24.10.0" This reverts commit c90f52e59b6db649524998146c96f5d89a266947. --- benchmarks/benchmarks/analysis/rms.py | 4 +- package/MDAnalysis/__init__.py | 8 +- package/MDAnalysis/analysis/align.py | 455 ++++------ .../MDAnalysis/analysis/atomicdistances.py | 15 +- package/MDAnalysis/analysis/base.py | 51 +- package/MDAnalysis/analysis/bat.py | 19 +- package/MDAnalysis/analysis/contacts.py | 8 +- package/MDAnalysis/analysis/density.py | 29 +- package/MDAnalysis/analysis/diffusionmap.py | 70 +- package/MDAnalysis/analysis/dihedrals.py | 46 +- package/MDAnalysis/analysis/distances.py | 4 +- package/MDAnalysis/analysis/dssp/dssp.py | 7 +- .../MDAnalysis/analysis/dssp/pydssp_numpy.py | 13 +- .../MDAnalysis/analysis/encore/bootstrap.py | 4 +- .../encore/clustering/ClusterCollection.py | 11 +- .../encore/clustering/ClusteringMethod.py | 20 +- .../analysis/encore/clustering/cluster.py | 21 +- .../analysis/encore/confdistmatrix.py | 54 +- .../MDAnalysis/analysis/encore/covariance.py | 16 +- .../DimensionalityReductionMethod.py | 28 +- .../reduce_dimensionality.py | 16 +- .../MDAnalysis/analysis/encore/similarity.py | 53 +- package/MDAnalysis/analysis/encore/utils.py | 12 +- package/MDAnalysis/analysis/gnm.py | 16 +- .../analysis/hbonds/hbond_autocorrel.py | 6 +- package/MDAnalysis/analysis/helix_analysis.py | 20 +- .../analysis/hydrogenbonds/hbond_analysis.py | 302 ++++--- .../hydrogenbonds/hbond_autocorrel.py | 34 +- .../hydrogenbonds/wbridge_analysis.py | 143 +++- package/MDAnalysis/analysis/leaflet.py | 5 +- package/MDAnalysis/analysis/legacy/x3dna.py | 46 +- package/MDAnalysis/analysis/lineardensity.py | 43 +- package/MDAnalysis/analysis/nucleicacids.py | 20 +- package/MDAnalysis/analysis/pca.py | 16 +- package/MDAnalysis/analysis/polymer.py | 7 +- package/MDAnalysis/analysis/rdf.py | 10 +- package/MDAnalysis/analysis/results.py | 12 +- package/MDAnalysis/analysis/rms.py | 73 +- package/MDAnalysis/auxiliary/EDR.py | 10 +- package/MDAnalysis/auxiliary/base.py | 37 +- package/MDAnalysis/converters/OpenMM.py | 12 +- package/MDAnalysis/converters/OpenMMParser.py | 4 +- package/MDAnalysis/converters/ParmEd.py | 33 +- package/MDAnalysis/converters/ParmEdParser.py | 4 +- .../MDAnalysis/converters/RDKitInferring.py | 33 +- package/MDAnalysis/converters/RDKitParser.py | 8 +- package/MDAnalysis/coordinates/CRD.py | 16 +- package/MDAnalysis/coordinates/DCD.py | 127 ++- package/MDAnalysis/coordinates/DLPoly.py | 41 +- package/MDAnalysis/coordinates/DMS.py | 8 +- package/MDAnalysis/coordinates/FHIAIMS.py | 8 +- package/MDAnalysis/coordinates/GMS.py | 64 +- package/MDAnalysis/coordinates/GRO.py | 48 +- package/MDAnalysis/coordinates/H5MD.py | 777 ++++++++---------- package/MDAnalysis/coordinates/LAMMPS.py | 64 +- package/MDAnalysis/coordinates/MMTF.py | 4 +- package/MDAnalysis/coordinates/MOL2.py | 74 +- package/MDAnalysis/coordinates/NAMDBIN.py | 4 +- package/MDAnalysis/coordinates/PDB.py | 502 +++++------ package/MDAnalysis/coordinates/PDBQT.py | 16 +- package/MDAnalysis/coordinates/PQR.py | 12 +- package/MDAnalysis/coordinates/TNG.py | 42 +- package/MDAnalysis/coordinates/TRC.py | 41 +- package/MDAnalysis/coordinates/TRJ.py | 453 +++++----- package/MDAnalysis/coordinates/TRR.py | 28 +- package/MDAnalysis/coordinates/TRZ.py | 422 +++++----- package/MDAnalysis/coordinates/TXYZ.py | 15 +- package/MDAnalysis/coordinates/XDR.py | 4 +- package/MDAnalysis/coordinates/XTC.py | 32 +- package/MDAnalysis/coordinates/XYZ.py | 76 +- package/MDAnalysis/coordinates/__init__.py | 2 +- package/MDAnalysis/coordinates/base.py | 266 +++--- package/MDAnalysis/coordinates/chain.py | 157 ++-- package/MDAnalysis/coordinates/memory.py | 154 ++-- package/MDAnalysis/core/_get_readers.py | 8 +- package/MDAnalysis/core/groups.py | 132 ++- package/MDAnalysis/core/selection.py | 626 +++++--------- package/MDAnalysis/core/topology.py | 5 +- package/MDAnalysis/core/topologyattrs.py | 93 ++- package/MDAnalysis/core/topologyobjects.py | 15 +- package/MDAnalysis/core/universe.py | 572 ++++++------- package/MDAnalysis/due.py | 4 +- package/MDAnalysis/guesser/base.py | 7 +- package/MDAnalysis/guesser/default_guesser.py | 21 +- package/MDAnalysis/lib/NeighborSearch.py | 4 +- package/MDAnalysis/lib/_distopia.py | 4 +- package/MDAnalysis/lib/distances.py | 28 +- package/MDAnalysis/lib/mdamath.py | 12 +- package/MDAnalysis/lib/picklable_file_io.py | 12 +- package/MDAnalysis/lib/pkdtree.py | 51 +- package/MDAnalysis/lib/transformations.py | 28 +- package/MDAnalysis/lib/util.py | 76 +- package/MDAnalysis/selections/base.py | 12 +- package/MDAnalysis/selections/charmm.py | 10 +- package/MDAnalysis/selections/pymol.py | 4 +- package/MDAnalysis/topology/CRDParser.py | 16 +- package/MDAnalysis/topology/DMSParser.py | 4 +- package/MDAnalysis/topology/GMSParser.py | 4 +- package/MDAnalysis/topology/GSDParser.py | 4 +- package/MDAnalysis/topology/ITPParser.py | 32 +- package/MDAnalysis/topology/LAMMPSParser.py | 28 +- package/MDAnalysis/topology/MMTFParser.py | 18 +- package/MDAnalysis/topology/MOL2Parser.py | 8 +- package/MDAnalysis/topology/PDBParser.py | 164 ++-- package/MDAnalysis/topology/PSFParser.py | 10 +- package/MDAnalysis/topology/TOPParser.py | 20 +- package/MDAnalysis/topology/TPRParser.py | 4 +- package/MDAnalysis/topology/__init__.py | 22 +- package/MDAnalysis/topology/base.py | 19 +- package/MDAnalysis/topology/guessers.py | 8 +- package/MDAnalysis/topology/tpr/obj.py | 4 +- package/MDAnalysis/topology/tpr/utils.py | 176 ++-- .../transformations/boxdimensions.py | 4 +- package/MDAnalysis/transformations/fit.py | 36 +- package/MDAnalysis/transformations/nojump.py | 11 +- .../transformations/positionaveraging.py | 4 +- package/MDAnalysis/transformations/rotate.py | 20 +- .../MDAnalysis/transformations/translate.py | 20 +- package/MDAnalysis/transformations/wrap.py | 12 +- package/MDAnalysis/units.py | 6 +- .../MDAnalysis/visualization/streamlines.py | 42 +- .../visualization/streamlines_3D.py | 91 +- package/doc/sphinx/source/conf.py | 4 +- package/setup.py | 27 +- .../MDAnalysisTests/analysis/test_align.py | 91 +- .../analysis/test_atomicdistances.py | 8 +- .../MDAnalysisTests/analysis/test_base.py | 44 +- .../MDAnalysisTests/analysis/test_bat.py | 14 +- .../MDAnalysisTests/analysis/test_contacts.py | 36 +- .../MDAnalysisTests/analysis/test_density.py | 32 +- .../analysis/test_dielectric.py | 4 +- .../analysis/test_diffusionmap.py | 16 +- .../analysis/test_dihedrals.py | 26 +- .../analysis/test_distances.py | 28 +- .../MDAnalysisTests/analysis/test_dssp.py | 24 +- .../MDAnalysisTests/analysis/test_encore.py | 142 ++-- .../MDAnalysisTests/analysis/test_gnm.py | 4 +- .../analysis/test_helix_analysis.py | 36 +- .../analysis/test_hydrogenbondautocorrel.py | 8 +- .../test_hydrogenbondautocorrel_deprecated.py | 8 +- .../analysis/test_hydrogenbonds_analysis.py | 68 +- .../MDAnalysisTests/analysis/test_leaflet.py | 18 +- .../analysis/test_lineardensity.py | 51 +- .../MDAnalysisTests/analysis/test_nuclinfo.py | 4 +- .../MDAnalysisTests/analysis/test_pca.py | 24 +- .../analysis/test_persistencelength.py | 4 +- .../MDAnalysisTests/analysis/test_rdf.py | 4 +- .../MDAnalysisTests/analysis/test_rdf_s.py | 8 +- .../MDAnalysisTests/analysis/test_results.py | 8 +- .../MDAnalysisTests/analysis/test_rms.py | 39 +- .../MDAnalysisTests/analysis/test_wbridge.py | 88 +- testsuite/MDAnalysisTests/auxiliary/base.py | 25 +- .../MDAnalysisTests/auxiliary/test_core.py | 16 +- .../MDAnalysisTests/auxiliary/test_edr.py | 51 +- .../MDAnalysisTests/auxiliary/test_xvg.py | 8 +- .../MDAnalysisTests/converters/test_base.py | 4 +- .../converters/test_openmm_parser.py | 8 +- .../MDAnalysisTests/converters/test_parmed.py | 19 +- .../converters/test_parmed_parser.py | 12 +- .../MDAnalysisTests/converters/test_rdkit.py | 71 +- .../converters/test_rdkit_parser.py | 21 +- testsuite/MDAnalysisTests/coordinates/base.py | 89 +- .../MDAnalysisTests/coordinates/reference.py | 12 +- .../coordinates/test_chainreader.py | 40 +- .../coordinates/test_chemfiles.py | 24 +- .../coordinates/test_copying.py | 4 +- .../MDAnalysisTests/coordinates/test_crd.py | 8 +- .../MDAnalysisTests/coordinates/test_dcd.py | 15 +- .../coordinates/test_dlpoly.py | 8 +- .../MDAnalysisTests/coordinates/test_dms.py | 7 +- .../coordinates/test_fhiaims.py | 44 +- .../MDAnalysisTests/coordinates/test_gms.py | 4 +- .../MDAnalysisTests/coordinates/test_gro.py | 16 +- .../MDAnalysisTests/coordinates/test_h5md.py | 119 ++- .../coordinates/test_lammps.py | 86 +- .../coordinates/test_memory.py | 24 +- .../MDAnalysisTests/coordinates/test_mol2.py | 12 +- .../coordinates/test_netcdf.py | 90 +- .../MDAnalysisTests/coordinates/test_pdb.py | 101 ++- .../MDAnalysisTests/coordinates/test_pdbqt.py | 4 +- .../MDAnalysisTests/coordinates/test_pqr.py | 4 +- .../coordinates/test_reader_api.py | 4 +- .../coordinates/test_timestep_api.py | 20 +- .../MDAnalysisTests/coordinates/test_tng.py | 52 +- .../MDAnalysisTests/coordinates/test_trc.py | 38 +- .../MDAnalysisTests/coordinates/test_trj.py | 15 +- .../MDAnalysisTests/coordinates/test_trz.py | 16 +- .../MDAnalysisTests/coordinates/test_txyz.py | 12 +- .../coordinates/test_writer_api.py | 12 +- .../coordinates/test_writer_registration.py | 4 +- .../MDAnalysisTests/coordinates/test_xdr.py | 64 +- .../MDAnalysisTests/core/test_accessors.py | 9 +- .../MDAnalysisTests/core/test_accumulate.py | 20 +- testsuite/MDAnalysisTests/core/test_atom.py | 4 +- .../MDAnalysisTests/core/test_atomgroup.py | 131 ++- .../core/test_atomselections.py | 77 +- .../core/test_group_traj_access.py | 46 +- testsuite/MDAnalysisTests/core/test_groups.py | 62 +- .../MDAnalysisTests/core/test_residuegroup.py | 11 +- .../MDAnalysisTests/core/test_topology.py | 4 +- .../core/test_topologyattrs.py | 20 +- .../core/test_topologyobjects.py | 16 +- .../MDAnalysisTests/core/test_universe.py | 133 ++- testsuite/MDAnalysisTests/core/test_unwrap.py | 32 +- .../core/test_updating_atomgroup.py | 24 +- testsuite/MDAnalysisTests/core/test_wrap.py | 36 +- testsuite/MDAnalysisTests/core/util.py | 4 +- testsuite/MDAnalysisTests/datafiles.py | 114 ++- testsuite/MDAnalysisTests/dummy.py | 8 +- .../MDAnalysisTests/formats/test_libdcd.py | 11 +- .../MDAnalysisTests/formats/test_libmdaxdr.py | 8 +- .../MDAnalysisTests/guesser/test_base.py | 19 +- .../guesser/test_default_guesser.py | 29 +- testsuite/MDAnalysisTests/lib/test_cutil.py | 4 +- .../MDAnalysisTests/lib/test_distances.py | 176 ++-- .../lib/test_neighborsearch.py | 4 +- testsuite/MDAnalysisTests/lib/test_nsgrid.py | 34 +- testsuite/MDAnalysisTests/lib/test_util.py | 138 +++- testsuite/MDAnalysisTests/test_api.py | 3 +- testsuite/MDAnalysisTests/topology/base.py | 12 +- .../MDAnalysisTests/topology/test_fhiaims.py | 4 +- .../MDAnalysisTests/topology/test_gms.py | 4 +- .../MDAnalysisTests/topology/test_guessers.py | 4 +- .../MDAnalysisTests/topology/test_itp.py | 20 +- .../topology/test_lammpsdata.py | 4 +- .../MDAnalysisTests/topology/test_minimal.py | 4 +- .../MDAnalysisTests/topology/test_mol2.py | 8 +- .../MDAnalysisTests/topology/test_pdb.py | 5 +- .../MDAnalysisTests/topology/test_pqr.py | 4 +- .../MDAnalysisTests/topology/test_top.py | 23 +- .../topology/test_topology_base.py | 4 +- .../topology/test_tprparser.py | 8 +- .../MDAnalysisTests/topology/test_txyz.py | 4 +- .../transformations/test_base.py | 4 +- .../transformations/test_boxdimensions.py | 16 +- .../transformations/test_fit.py | 4 +- .../transformations/test_nojump.py | 16 +- .../transformations/test_positionaveraging.py | 8 +- .../transformations/test_rotate.py | 22 +- .../transformations/test_translate.py | 12 +- .../transformations/test_wrap.py | 8 +- testsuite/MDAnalysisTests/util.py | 7 +- .../MDAnalysisTests/utils/test_authors.py | 4 +- .../MDAnalysisTests/utils/test_duecredit.py | 5 +- .../MDAnalysisTests/utils/test_failure.py | 4 +- .../MDAnalysisTests/utils/test_imports.py | 4 +- testsuite/MDAnalysisTests/utils/test_meta.py | 4 +- .../MDAnalysisTests/utils/test_modelling.py | 51 +- .../MDAnalysisTests/utils/test_pickleio.py | 16 +- .../MDAnalysisTests/utils/test_qcprot.py | 4 +- .../MDAnalysisTests/utils/test_selections.py | 8 +- .../MDAnalysisTests/utils/test_streamio.py | 12 +- .../utils/test_transformations.py | 8 +- testsuite/MDAnalysisTests/utils/test_units.py | 4 +- .../visualization/test_streamlines.py | 8 +- 255 files changed, 6593 insertions(+), 4798 deletions(-) diff --git a/benchmarks/benchmarks/analysis/rms.py b/benchmarks/benchmarks/analysis/rms.py index 2f5b91f399..80afc15f18 100644 --- a/benchmarks/benchmarks/analysis/rms.py +++ b/benchmarks/benchmarks/analysis/rms.py @@ -28,9 +28,7 @@ def setup(self, num_atoms, use_weights, center, superposition): self.u.trajectory[-1] self.B = self.u.atoms.positions.copy()[:num_atoms] self.atoms = self.u.atoms[:num_atoms] - self.weights = ( - self.atoms.masses / np.sum(self.atoms.masses) if use_weights else None - ) + self.weights = self.atoms.masses/np.sum(self.atoms.masses) if use_weights else None def time_rmsd(self, num_atoms, weights, center, superposition): """Benchmark rmsd function using a setup similar to diff --git a/package/MDAnalysis/__init__.py b/package/MDAnalysis/__init__.py index 9cb8ca9764..6843c3738a 100644 --- a/package/MDAnalysis/__init__.py +++ b/package/MDAnalysis/__init__.py @@ -179,7 +179,9 @@ _CONVERTERS: Dict = {} # Registry of TopologyAttributes _TOPOLOGY_ATTRS: Dict = {} # {attrname: cls} -_TOPOLOGY_TRANSPLANTS: Dict = {} # {name: [attrname, method, transplant class]} +_TOPOLOGY_TRANSPLANTS: Dict = ( + {} +) # {name: [attrname, method, transplant class]} _TOPOLOGY_ATTRNAMES: Dict = {} # {lower case name w/o _ : name} _GUESSERS: Dict = {} @@ -202,7 +204,9 @@ del logging # only MDAnalysis DeprecationWarnings are loud by default -warnings.filterwarnings(action="once", category=DeprecationWarning, module="MDAnalysis") +warnings.filterwarnings( + action="once", category=DeprecationWarning, module="MDAnalysis" +) from . import units diff --git a/package/MDAnalysis/analysis/align.py b/package/MDAnalysis/analysis/align.py index e7b6e482eb..acf87dbf65 100644 --- a/package/MDAnalysis/analysis/align.py +++ b/package/MDAnalysis/analysis/align.py @@ -212,13 +212,13 @@ import MDAnalysis.analysis.rms as rms from MDAnalysis.coordinates.memory import MemoryReader from MDAnalysis.lib.util import get_weights -from MDAnalysis.lib.util import deprecate # remove 3.0 +from MDAnalysis.lib.util import deprecate # remove 3.0 from MDAnalysis.lib.log import ProgressBar from ..due import due, Doi from .base import AnalysisBase -logger = logging.getLogger("MDAnalysis.analysis.align") +logger = logging.getLogger('MDAnalysis.analysis.align') def rotation_matrix(a, b, weights=None): @@ -280,6 +280,7 @@ def rotation_matrix(a, b, weights=None): AlignTraj: Fit a whole trajectory. """ + a = np.asarray(a, dtype=np.float64) b = np.asarray(b, dtype=np.float64) @@ -306,9 +307,8 @@ def rotation_matrix(a, b, weights=None): return rot.reshape(3, 3), rmsd -def _fit_to( - mobile_coordinates, ref_coordinates, mobile_atoms, mobile_com, ref_com, weights=None -): +def _fit_to(mobile_coordinates, ref_coordinates, mobile_atoms, + mobile_com, ref_com, weights=None): r"""Perform an rmsd-fitting to determine rotation matrix and align atoms Parameters @@ -356,7 +356,8 @@ def _fit_to( where :math:`\bar{X}` is the center. """ - R, min_rmsd = rotation_matrix(mobile_coordinates, ref_coordinates, weights=weights) + R, min_rmsd = rotation_matrix(mobile_coordinates, ref_coordinates, + weights=weights) mobile_atoms.translate(-mobile_com) mobile_atoms.rotate(R) @@ -365,16 +366,9 @@ def _fit_to( return mobile_atoms, min_rmsd -def alignto( - mobile, - reference, - select=None, - weights=None, - subselection=None, - tol_mass=0.1, - strict=False, - match_atoms=True, -): +def alignto(mobile, reference, select=None, weights=None, + subselection=None, tol_mass=0.1, strict=False, + match_atoms=True): """Perform a spatial superposition by minimizing the RMSD. Spatially align the group of atoms `mobile` to `reference` by @@ -500,7 +494,7 @@ def alignto( .. versionchanged:: 0.17.0 Deprecated keyword `mass_weighted` was removed. """ - if select in ("all", None): + if select in ('all', None): # keep the EXACT order in the input AtomGroups; select_atoms('all') # orders them by index, which can lead to wrong results if the user # has crafted mobile and reference to match atom by atom @@ -508,16 +502,14 @@ def alignto( ref_atoms = reference.atoms else: select = rms.process_selection(select) - mobile_atoms = mobile.select_atoms(*select["mobile"]) - ref_atoms = reference.select_atoms(*select["reference"]) - - ref_atoms, mobile_atoms = get_matching_atoms( - ref_atoms, - mobile_atoms, - tol_mass=tol_mass, - strict=strict, - match_atoms=match_atoms, - ) + mobile_atoms = mobile.select_atoms(*select['mobile']) + ref_atoms = reference.select_atoms(*select['reference']) + + + ref_atoms, mobile_atoms = get_matching_atoms(ref_atoms, mobile_atoms, + tol_mass=tol_mass, + strict=strict, + match_atoms=match_atoms) weights = get_weights(ref_atoms, weights) @@ -540,38 +532,26 @@ def alignto( # treat subselection as AtomGroup mobile_atoms = subselection.atoms except AttributeError: - err = ( - "subselection must be a selection string, an" - " AtomGroup or Universe or None" - ) + err = ("subselection must be a selection string, an" + " AtomGroup or Universe or None") raise TypeError(err) from None + # _fit_to DOES subtract center of mass, will provide proper min_rmsd - mobile_atoms, new_rmsd = _fit_to( - mobile_coordinates, - ref_coordinates, - mobile_atoms, - mobile_com, - ref_com, - weights=weights, - ) + mobile_atoms, new_rmsd = _fit_to(mobile_coordinates, ref_coordinates, + mobile_atoms, mobile_com, ref_com, + weights=weights) return old_rmsd, new_rmsd @due.dcite( - Doi("10.1021/acs.jpcb.7b11988"), - description="Iterative Calculation of Opimal Reference", - path="MDAnalysis.analysis.align.iterative_average", + Doi("10.1021/acs.jpcb.7b11988"), + description="Iterative Calculation of Opimal Reference", + path="MDAnalysis.analysis.align.iterative_average" ) def iterative_average( - mobile, - reference=None, - select="all", - weights=None, - niter=100, - eps=1e-6, - verbose=False, - **kwargs, + mobile, reference=None, select='all', weights=None, niter=100, + eps=1e-6, verbose=False, **kwargs ): """Iteratively calculate an optimal reference that is also the average structure after an RMSD alignment. @@ -638,8 +618,8 @@ def iterative_average( reference = mobile select = rms.process_selection(select) - ref = mda.Merge(reference.select_atoms(*select["reference"])) - sel_mobile = select["mobile"][0] + ref = mda.Merge(reference.select_atoms(*select['reference'])) + sel_mobile = select['mobile'][0] weights = get_weights(ref.atoms, weights) @@ -650,15 +630,13 @@ def iterative_average( break avg_struc = AverageStructure( - mobile, - reference=ref, - select={"mobile": sel_mobile, "reference": "all"}, - weights=weights, - **kwargs, + mobile, reference=ref, select={ + 'mobile': sel_mobile, 'reference': 'all' + }, + weights=weights, **kwargs ).run() - drmsd = rms.rmsd( - ref.atoms.positions, avg_struc.results.positions, weights=weights - ) + drmsd = rms.rmsd(ref.atoms.positions, avg_struc.results.positions, + weights=weights) ref = avg_struc.results.universe if verbose: @@ -700,22 +678,11 @@ class AlignTraj(AnalysisBase): """ - def __init__( - self, - mobile, - reference, - select="all", - filename=None, - prefix="rmsfit_", - weights=None, - tol_mass=0.1, - match_atoms=True, - strict=False, - force=True, - in_memory=False, - writer_kwargs=None, - **kwargs, - ): + def __init__(self, mobile, reference, select='all', filename=None, + prefix='rmsfit_', weights=None, + tol_mass=0.1, match_atoms=True, strict=False, force=True, in_memory=False, + writer_kwargs=None, + **kwargs): """Parameters ---------- mobile : Universe @@ -821,8 +788,8 @@ def __init__( """ select = rms.process_selection(select) - self.ref_atoms = reference.select_atoms(*select["reference"]) - self.mobile_atoms = mobile.select_atoms(*select["mobile"]) + self.ref_atoms = reference.select_atoms(*select['reference']) + self.mobile_atoms = mobile.select_atoms(*select['mobile']) if in_memory or isinstance(mobile.trajectory, MemoryReader): mobile.transfer_to_memory() filename = None @@ -831,15 +798,13 @@ def __init__( if filename is None: fn = os.path.split(mobile.trajectory.filename)[1] filename = prefix + fn - logger.info( - "filename of rms_align with no filename given" - ": {0}".format(filename) - ) + logger.info('filename of rms_align with no filename given' + ': {0}'.format(filename)) if os.path.exists(filename) and not force: raise IOError( - "Filename already exists in path and force is not set" " to True" - ) + 'Filename already exists in path and force is not set' + ' to True') # do this after setting the memory reader to have a reference to the # right reader. @@ -854,12 +819,8 @@ def __init__( natoms = self.mobile.n_atoms self.ref_atoms, self.mobile_atoms = get_matching_atoms( - self.ref_atoms, - self.mobile_atoms, - tol_mass=tol_mass, - strict=strict, - match_atoms=match_atoms, - ) + self.ref_atoms, self.mobile_atoms, tol_mass=tol_mass, + strict=strict, match_atoms=match_atoms) if writer_kwargs is None: writer_kwargs = {} @@ -884,13 +845,11 @@ def _single_frame(self): mobile_com = self.mobile_atoms.center(self._weights) mobile_coordinates = self.mobile_atoms.positions - mobile_com mobile_atoms, self.results.rmsd[index] = _fit_to( - mobile_coordinates, - self._ref_coordinates, - self.mobile, - mobile_com, - self._ref_com, - self._weights, - ) + mobile_coordinates, + self._ref_coordinates, + self.mobile, + mobile_com, + self._ref_com, self._weights) # write whole aligned input trajectory system self._writer.write(mobile_atoms) @@ -901,11 +860,9 @@ def _conclude(self): @property def rmsd(self): - wmsg = ( - "The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 and " - "will be removed in MDAnalysis 3.0.0. Please use " - "`results.rmsd` instead." - ) + wmsg = ("The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 and " + "will be removed in MDAnalysis 3.0.0. Please use " + "`results.rmsd` instead.") warnings.warn(wmsg, DeprecationWarning) return self.results.rmsd @@ -939,21 +896,10 @@ class AverageStructure(AnalysisBase): """ - def __init__( - self, - mobile, - reference=None, - select="all", - filename=None, - weights=None, - tol_mass=0.1, - match_atoms=True, - strict=False, - force=True, - in_memory=False, - ref_frame=0, - **kwargs, - ): + def __init__(self, mobile, reference=None, select='all', filename=None, + weights=None, + tol_mass=0.1, match_atoms=True, strict=False, force=True, in_memory=False, + ref_frame=0, **kwargs): """Parameters ---------- mobile : Universe @@ -1071,20 +1017,18 @@ def __init__( self.reference = reference if reference is not None else mobile select = rms.process_selection(select) - self.ref_atoms = self.reference.select_atoms(*select["reference"]) - self.mobile_atoms = mobile.select_atoms(*select["mobile"]) + self.ref_atoms = self.reference.select_atoms(*select['reference']) + self.mobile_atoms = mobile.select_atoms(*select['mobile']) if len(self.ref_atoms) != len(self.mobile_atoms): - err = ( - "Reference and trajectory atom selections do " - "not contain the same number of atoms: " - "N_ref={0:d}, N_traj={1:d}".format( - self.ref_atoms.n_atoms, self.mobile_atoms.n_atoms - ) - ) + err = ("Reference and trajectory atom selections do " + "not contain the same number of atoms: " + "N_ref={0:d}, N_traj={1:d}".format(self.ref_atoms.n_atoms, + self.mobile_atoms.n_atoms)) logger.exception(err) raise SelectionError(err) - logger.info("RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms))) + logger.info("RMS calculation " + "for {0:d} atoms.".format(len(self.ref_atoms))) # store reference to mobile atoms self.mobile = mobile.atoms @@ -1095,12 +1039,8 @@ def __init__( natoms = len(self.results.universe.atoms) self.ref_atoms, self.mobile_atoms = get_matching_atoms( - self.ref_atoms, - self.mobile_atoms, - tol_mass=tol_mass, - strict=strict, - match_atoms=match_atoms, - ) + self.ref_atoms, self.mobile_atoms, tol_mass=tol_mass, + strict=strict, match_atoms=match_atoms) # with self.filename == None (in_memory), the NullWriter is chosen # (which just ignores input) and so only the in_memory trajectory is @@ -1132,20 +1072,18 @@ def _prepare(self): def _single_frame(self): mobile_com = self.mobile_atoms.center(self._weights) mobile_coordinates = self.mobile_atoms.positions - mobile_com - self.results.rmsd += _fit_to( - mobile_coordinates, - self._ref_coordinates, - self.mobile, - mobile_com, - self._ref_com, - self._weights, - )[1] + self.results.rmsd += _fit_to(mobile_coordinates, + self._ref_coordinates, + self.mobile, + mobile_com, + self._ref_com, self._weights)[1] self.results.positions += self.mobile_atoms.positions def _conclude(self): self.results.positions /= self.n_frames self.results.rmsd /= self.n_frames - self.results.universe.load_new(self.results.positions.reshape((1, -1, 3))) + self.results.universe.load_new( + self.results.positions.reshape((1, -1, 3))) self._writer.write(self.results.universe.atoms) self._writer.close() if not self._verbose: @@ -1153,49 +1091,34 @@ def _conclude(self): @property def universe(self): - wmsg = ( - "The `universe` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.universe` instead." - ) + wmsg = ("The `universe` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.universe` instead.") warnings.warn(wmsg, DeprecationWarning) return self.results.universe @property def positions(self): - wmsg = ( - "The `positions` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.positions` instead." - ) + wmsg = ("The `positions` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.positions` instead.") warnings.warn(wmsg, DeprecationWarning) return self.results.positions @property def rmsd(self): - wmsg = ( - "The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.rmsd` instead." - ) + wmsg = ("The `rmsd` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.rmsd` instead.") warnings.warn(wmsg, DeprecationWarning) return self.results.rmsd -@deprecate( - release="2.4.0", - remove="3.0", - message="See the documentation under Notes on how to directly use" - "Bio.Align.PairwiseAligner with ResidueGroups.", -) -def sequence_alignment( - mobile, - reference, - match_score=2, - mismatch_penalty=-1, - gap_penalty=-2, - gapextension_penalty=-0.1, -): +@deprecate(release="2.4.0", remove="3.0", + message="See the documentation under Notes on how to directly use" + "Bio.Align.PairwiseAligner with ResidueGroups.") +def sequence_alignment(mobile, reference, match_score=2, mismatch_penalty=-1, + gap_penalty=-2, gapextension_penalty=-0.1): """Generate a global sequence alignment between two residue groups. The residues in `reference` and `mobile` will be globally aligned. @@ -1278,11 +1201,9 @@ def sequence_alignment( """ if not HAS_BIOPYTHON: - errmsg = ( - "The `sequence_alignment` method requires an installation " - "of `Biopython`. Please install `Biopython` to use this " - "method: https://biopython.org/wiki/Download" - ) + errmsg = ("The `sequence_alignment` method requires an installation " + "of `Biopython`. Please install `Biopython` to use this " + "method: https://biopython.org/wiki/Download") raise ImportError(errmsg) aligner = Bio.Align.PairwiseAligner( @@ -1290,42 +1211,28 @@ def sequence_alignment( match_score=match_score, mismatch_score=mismatch_penalty, open_gap_score=gap_penalty, - extend_gap_score=gapextension_penalty, - ) - aln = aligner.align( - reference.residues.sequence(format="Seq"), - mobile.residues.sequence(format="Seq"), - ) + extend_gap_score=gapextension_penalty) + aln = aligner.align(reference.residues.sequence(format="Seq"), + mobile.residues.sequence(format="Seq")) # choose top alignment with highest score topalignment = aln[0] # reconstruct the results tuple that used to be of type Bio.pairwise2.Alignment AlignmentTuple = collections.namedtuple( - "Alignment", ["seqA", "seqB", "score", "start", "end"] - ) + "Alignment", + ["seqA", "seqB", "score", "start", "end"]) # start/stop are not particularly meaningful and there's no obvious way to # get the old pairwise2 start/stop from the new PairwiseAligner output. - return AlignmentTuple( - topalignment[0], - topalignment[1], - topalignment.score, - 0, - max(reference.n_residues, mobile.n_residues), - ) + return AlignmentTuple(topalignment[0], topalignment[1], + topalignment.score, + 0, max(reference.n_residues, mobile.n_residues)) -def fasta2select( - fastafilename, - is_aligned=False, - ref_resids=None, - target_resids=None, - ref_offset=0, - target_offset=0, - verbosity=3, - alnfilename=None, - treefilename=None, - clustalw="clustalw2", -): + +def fasta2select(fastafilename, is_aligned=False, + ref_resids=None, target_resids=None, + ref_offset=0, target_offset=0, verbosity=3, + alnfilename=None, treefilename=None, clustalw="clustalw2"): """Return selection strings that will select equivalent residues. The function aligns two sequences provided in a FASTA file and @@ -1400,7 +1307,7 @@ def fasta2select( :func:`sequence_alignment`, which does not require external programs. - + Raises ------ ImportError @@ -1418,52 +1325,53 @@ def fasta2select( """ if not HAS_BIOPYTHON: - errmsg = ( - "The `fasta2select` method requires an installation " - "of `Biopython`. Please install `Biopython` to use this " - "method: https://biopython.org/wiki/Download" - ) + errmsg = ("The `fasta2select` method requires an installation " + "of `Biopython`. Please install `Biopython` to use this " + "method: https://biopython.org/wiki/Download") raise ImportError(errmsg) if is_aligned: logger.info("Using provided alignment {}".format(fastafilename)) with open(fastafilename) as fasta: - alignment = Bio.AlignIO.read(fasta, "fasta") + alignment = Bio.AlignIO.read( + fasta, "fasta") else: if alnfilename is None: filepath, ext = os.path.splitext(fastafilename) - alnfilename = os.path.basename(filepath) + ".aln" + alnfilename = os.path.basename(filepath) + '.aln' if treefilename is None: filepath, ext = os.path.splitext(alnfilename) - treefilename = os.path.basename(filepath) + ".dnd" + treefilename = os.path.basename(filepath) + '.dnd' run_clustalw = Bio.Align.Applications.ClustalwCommandline( clustalw, infile=fastafilename, type="protein", align=True, outfile=alnfilename, - newtree=treefilename, - ) + newtree=treefilename) logger.debug( - "Aligning sequences in %(fastafilename)r with %(clustalw)r.", vars() - ) + "Aligning sequences in %(fastafilename)r with %(clustalw)r.", + vars()) logger.debug("ClustalW commandline: %r", str(run_clustalw)) try: stdout, stderr = run_clustalw() except: logger.exception("ClustalW %(clustalw)r failed", vars()) - logger.info("(You can get clustalw2 from http://www.clustal.org/clustal2/)") + logger.info( + "(You can get clustalw2 from http://www.clustal.org/clustal2/)") raise with open(alnfilename) as aln: - alignment = Bio.AlignIO.read(aln, "clustal") - logger.info("Using clustalw sequence alignment {0!r}".format(alnfilename)) + alignment = Bio.AlignIO.read( + aln, "clustal") logger.info( - "ClustalW Newick guide tree was also produced: {0!r}".format(treefilename) - ) + "Using clustalw sequence alignment {0!r}".format(alnfilename)) + logger.info( + "ClustalW Newick guide tree was also produced: {0!r}".format(treefilename)) nseq = len(alignment) if nseq != 2: - raise ValueError("Only two sequences in the alignment can be processed.") + raise ValueError( + "Only two sequences in the alignment can be processed.") # implict assertion that we only have two sequences in the alignment orig_resids = [ref_resids, target_resids] @@ -1479,7 +1387,8 @@ def fasta2select( else: orig_resids[iseq] = np.asarray(orig_resids[iseq]) # add offsets to the sequence <--> resid translation table - seq2resids = [resids + offset for resids, offset in zip(orig_resids, offsets)] + seq2resids = [resids + offset for resids, offset in zip( + orig_resids, offsets)] del orig_resids del offsets @@ -1515,9 +1424,8 @@ def resid_factory(alignment, seq2resids): t = np.zeros((nseq, alignment.get_alignment_length()), dtype=int) for iseq, a in enumerate(alignment): GAP = "-" - t[iseq, :] = seq2resids[iseq][ - np.cumsum(np.where(np.array(list(a.seq)) == GAP, 0, 1)) - 1 - ] + t[iseq, :] = seq2resids[iseq][np.cumsum(np.where( + np.array(list(a.seq)) == GAP, 0, 1)) - 1] # -1 because seq2resid is index-1 based (resids start at 1) def resid(nseq, ipos, t=t): @@ -1536,7 +1444,7 @@ def resid(nseq, ipos, t=t): if GAP in aligned: continue # skip residue template = "resid %i" - if "G" not in aligned: + if 'G' not in aligned: # can use CB template += " and ( backbone or name CB )" else: @@ -1549,7 +1457,7 @@ def resid(nseq, ipos, t=t): ref_selection = " or ".join(sel[0]) target_selection = " or ".join(sel[1]) - return {"reference": ref_selection, "mobile": target_selection} + return {'reference': ref_selection, 'mobile': target_selection} def get_matching_atoms(ag1, ag2, tol_mass=0.1, strict=False, match_atoms=True): @@ -1627,39 +1535,34 @@ def get_matching_atoms(ag1, ag2, tol_mass=0.1, strict=False, match_atoms=True): if ag1.n_atoms != ag2.n_atoms: if not match_atoms: - errmsg = ( - "Mobile and reference atom selections do not " - "contain the same number of atoms and atom " - "matching is turned off. To match atoms based " - "on residue and mass, try match_atoms=True" - ) + errmsg = ("Mobile and reference atom selections do not " + "contain the same number of atoms and atom " + "matching is turned off. To match atoms based " + "on residue and mass, try match_atoms=True") logger.error(errmsg) raise SelectionError(errmsg) if ag1.n_residues != ag2.n_residues: - errmsg = ( - "Reference and trajectory atom selections do not contain " - "the same number of atoms: \n" - "atoms: N_ref={0}, N_traj={1}\n" - "and also not the same number of residues:\n" - "residues: N_ref={2}, N_traj={3}" - ).format(ag1.n_atoms, ag2.n_atoms, ag1.n_residues, ag2.n_residues) + errmsg = ("Reference and trajectory atom selections do not contain " + "the same number of atoms: \n" + "atoms: N_ref={0}, N_traj={1}\n" + "and also not the same number of residues:\n" + "residues: N_ref={2}, N_traj={3}").format( + ag1.n_atoms, ag2.n_atoms, + ag1.n_residues, ag2.n_residues) logger.error(errmsg) raise SelectionError(errmsg) else: - msg = ( - "Reference and trajectory atom selections do not contain " - "the same number of atoms: \n" - "atoms: N_ref={0}, N_traj={1}" - ).format(ag1.n_atoms, ag2.n_atoms) + msg = ("Reference and trajectory atom selections do not contain " + "the same number of atoms: \n" + "atoms: N_ref={0}, N_traj={1}").format( + ag1.n_atoms, ag2.n_atoms) if strict: logger.error(msg) raise SelectionError(msg) # continue with trying to create a valid selection - msg += ( - "\nbut we attempt to create a valid selection " - + "(use strict=True to disable this heuristic)." - ) + msg += ("\nbut we attempt to create a valid selection " + + "(use strict=True to disable this heuristic).") logger.info(msg) warnings.warn(msg, category=SelectionWarning) @@ -1687,7 +1590,7 @@ def get_matching_atoms(ag1, ag2, tol_mass=0.1, strict=False, match_atoms=True): rsize1 = np.array([r.atoms.n_atoms for r in ag1.residues]) rsize2 = np.array([r.atoms.n_atoms for r in ag2.residues]) rsize_mismatches = np.absolute(rsize1 - rsize2) - mismatch_mask = rsize_mismatches > 0 + mismatch_mask = (rsize_mismatches > 0) if np.any(mismatch_mask): def get_atoms_byres(g, match_mask=None): @@ -1697,7 +1600,7 @@ def get_atoms_byres(g, match_mask=None): match_mask = np.logical_not(mismatch_mask) ag = g.atoms good = ag.residues.resids[match_mask] # resid for each residue - resids = ag.resids # resid for each atom + resids = ag.resids # resid for each atom # boolean array for all matching atoms ix_good = np.isin(resids, good) return ag[ix_good] @@ -1709,21 +1612,12 @@ def get_atoms_byres(g, match_mask=None): # diagnostics mismatch_resindex = np.arange(ag1.n_residues)[mismatch_mask] - logger.warning( - "Removed {0} residues with non-matching numbers of atoms".format( - mismatch_mask.sum() - ) - ) - logger.debug( - "Removed residue ids: group 1: {0}".format( - ag1.residues.resids[mismatch_resindex] - ) - ) - logger.debug( - "Removed residue ids: group 2: {0}".format( - ag2.residues.resids[mismatch_resindex] - ) - ) + logger.warning("Removed {0} residues with non-matching numbers of atoms" + .format(mismatch_mask.sum())) + logger.debug("Removed residue ids: group 1: {0}" + .format(ag1.residues.resids[mismatch_resindex])) + logger.debug("Removed residue ids: group 2: {0}" + .format(ag2.residues.resids[mismatch_resindex])) # replace after logging (still need old ag1 and ag2 for # diagnostics) ag1 = _ag1 @@ -1732,10 +1626,8 @@ def get_atoms_byres(g, match_mask=None): # stop if we created empty selections (by removing ALL residues...) if ag1.n_atoms == 0 or ag2.n_atoms == 0: - errmsg = ( - "Failed to automatically find matching atoms: created empty selections. " - "Try to improve your selections for mobile and reference." - ) + errmsg = ("Failed to automatically find matching atoms: created empty selections. " + "Try to improve your selections for mobile and reference.") logger.error(errmsg) raise SelectionError(errmsg) @@ -1744,18 +1636,17 @@ def get_atoms_byres(g, match_mask=None): # good and can easily be misled (e.g., when one of the selections # had fewer atoms but the residues in mobile and reference have # each the same number) - if not hasattr(ag1, "masses") or not hasattr(ag2, "masses"): + if (not hasattr(ag1, 'masses') or not hasattr(ag2, 'masses')): msg = "Atoms could not be matched since they don't contain masses." logger.info(msg) warnings.warn(msg, category=SelectionWarning) else: try: - mass_mismatches = np.absolute(ag1.masses - ag2.masses) > tol_mass + mass_mismatches = (np.absolute(ag1.masses - ag2.masses) > tol_mass) except ValueError: - errmsg = ( - "Failed to find matching atoms: len(reference) = {}, len(mobile) = {} " - "Try to improve your selections for mobile and reference." - ).format(ag1.n_atoms, ag2.n_atoms) + errmsg = ("Failed to find matching atoms: len(reference) = {}, len(mobile) = {} " + "Try to improve your selections for mobile and reference.").format( + ag1.n_atoms, ag2.n_atoms) logger.error(errmsg) raise SelectionError(errmsg) from None @@ -1775,13 +1666,9 @@ def get_atoms_byres(g, match_mask=None): at.resid, at.resname, at.name, - at.mass, - ) - ) - errmsg = ( - "Inconsistent selections, masses differ by more than {0}; " - "mis-matching atoms are shown above." - ).format(tol_mass) + at.mass)) + errmsg = ("Inconsistent selections, masses differ by more than {0}; " + "mis-matching atoms are shown above.").format(tol_mass) logger.error(errmsg) raise SelectionError(errmsg) diff --git a/package/MDAnalysis/analysis/atomicdistances.py b/package/MDAnalysis/analysis/atomicdistances.py index 5cf15128d8..1860d3285b 100644 --- a/package/MDAnalysis/analysis/atomicdistances.py +++ b/package/MDAnalysis/analysis/atomicdistances.py @@ -150,12 +150,15 @@ class AtomicDistances(AnalysisBase): def __init__(self, ag1, ag2, pbc=True, **kwargs): # check ag1 and ag2 have the same number of atoms if ag1.atoms.n_atoms != ag2.atoms.n_atoms: - raise ValueError("AtomGroups do not " "have the same number of atoms") + raise ValueError("AtomGroups do not " + "have the same number of atoms") # check ag1 and ag2 are from the same trajectory elif ag1.universe.trajectory != ag2.universe.trajectory: - raise ValueError("AtomGroups are not " "from the same trajectory") + raise ValueError("AtomGroups are not " + "from the same trajectory") - super(AtomicDistances, self).__init__(ag1.universe.trajectory, **kwargs) + super(AtomicDistances, self).__init__(ag1.universe.trajectory, + **kwargs) self._ag1 = ag1 self._ag2 = ag2 @@ -168,6 +171,6 @@ def _prepare(self): def _single_frame(self): # if PBCs considered, get box size box = self._ag1.dimensions if self._pbc else None - self.results[self._frame_index] = calc_bonds( - self._ag1.positions, self._ag2.positions, box - ) + self.results[self._frame_index] = calc_bonds(self._ag1.positions, + self._ag2.positions, + box) diff --git a/package/MDAnalysis/analysis/base.py b/package/MDAnalysis/analysis/base.py index 80c390fd46..f18b866951 100644 --- a/package/MDAnalysis/analysis/base.py +++ b/package/MDAnalysis/analysis/base.py @@ -387,10 +387,14 @@ def _define_run_frames( self._trajectory = trajectory if frames is not None: if not all(opt is None for opt in [start, stop, step]): - raise ValueError("start/stop/step cannot be combined with frames") + raise ValueError( + "start/stop/step cannot be combined with frames" + ) slicer = frames else: - start, stop, step = trajectory.check_slice_indices(start, stop, step) + start, stop, step = trajectory.check_slice_indices( + start, stop, step + ) slicer = slice(start, stop, step) self.start, self.stop, self.step = start, stop, step return slicer @@ -413,7 +417,9 @@ def _prepare_sliced_trajectory(self, slicer: Union[slice, np.ndarray]): self.frames = np.zeros(self.n_frames, dtype=int) self.times = np.zeros(self.n_frames) - def _setup_frames(self, trajectory, start=None, stop=None, step=None, frames=None): + def _setup_frames( + self, trajectory, start=None, stop=None, step=None, frames=None + ): """Pass a Reader object and define the desired iteration pattern through the trajectory @@ -533,7 +539,9 @@ def _compute( progressbar_kwargs = {} logger.info("Choosing frames to analyze") # if verbose unchanged, use class default - verbose = getattr(self, "_verbose", False) if verbose is None else verbose + verbose = ( + getattr(self, "_verbose", False) if verbose is None else verbose + ) frames = indexed_frames[:, 1] @@ -544,7 +552,9 @@ def _compute( return self for idx, ts in enumerate( - ProgressBar(self._sliced_trajectory, verbose=verbose, **progressbar_kwargs) + ProgressBar( + self._sliced_trajectory, verbose=verbose, **progressbar_kwargs + ) ): self._frame_index = idx # accessed later by subclasses self._ts = ts @@ -597,7 +607,9 @@ def _setup_computation_groups( .. versionadded:: 2.8.0 """ if frames is None: - start, stop, step = self._trajectory.check_slice_indices(start, stop, step) + start, stop, step = self._trajectory.check_slice_indices( + start, stop, step + ) used_frames = np.arange(start, stop, step) elif not all(opt is None for opt in [start, stop, step]): raise ValueError("start/stop/step cannot be combined with frames") @@ -609,7 +621,9 @@ def _setup_computation_groups( used_frames = arange[used_frames] # similar to list(enumerate(frames)) - enumerated_frames = np.vstack([np.arange(len(used_frames)), used_frames]).T + enumerated_frames = np.vstack( + [np.arange(len(used_frames)), used_frames] + ).T if len(enumerated_frames) == 0: return [np.empty((0, 2), dtype=np.int64)] elif len(enumerated_frames) < n_parts: @@ -731,7 +745,9 @@ def _configure_backend( # or pass along an instance of the class itself # after ensuring it has apply method - if not isinstance(backend, BackendBase) or not hasattr(backend, "apply"): + if not isinstance(backend, BackendBase) or not hasattr( + backend, "apply" + ): raise ValueError( ( f"{backend=} is invalid: should have 'apply' method " @@ -819,18 +835,23 @@ def run( # default to serial execution backend = "serial" if backend is None else backend - progressbar_kwargs = {} if progressbar_kwargs is None else progressbar_kwargs + progressbar_kwargs = ( + {} if progressbar_kwargs is None else progressbar_kwargs + ) if (progressbar_kwargs or verbose) and not ( backend == "serial" or isinstance(backend, BackendSerial) ): - raise ValueError("Can not display progressbar with non-serial backend") + raise ValueError( + "Can not display progressbar with non-serial backend" + ) # if number of workers not specified, try getting the number from # the backend instance if possible, or set to 1 if n_workers is None: n_workers = ( backend.n_workers - if isinstance(backend, BackendBase) and hasattr(backend, "n_workers") + if isinstance(backend, BackendBase) + and hasattr(backend, "n_workers") else 1 ) @@ -995,7 +1016,9 @@ def _get_aggregator(self): return ResultsGroup({"timeseries": ResultsGroup.flatten_sequence}) def _single_frame(self): - self.results.timeseries.append(self.function(*self.args, **self.kwargs)) + self.results.timeseries.append( + self.function(*self.args, **self.kwargs) + ) def _conclude(self): self.results.frames = self.frames @@ -1056,7 +1079,9 @@ def RotationMatrix(mobile, ref): class WrapperClass(AnalysisFromFunction): def __init__(self, trajectory=None, *args, **kwargs): - super(WrapperClass, self).__init__(function, trajectory, *args, **kwargs) + super(WrapperClass, self).__init__( + function, trajectory, *args, **kwargs + ) @classmethod def get_supported_backends(cls): diff --git a/package/MDAnalysis/analysis/bat.py b/package/MDAnalysis/analysis/bat.py index 0e2adbc056..9b08c7dbff 100644 --- a/package/MDAnalysis/analysis/bat.py +++ b/package/MDAnalysis/analysis/bat.py @@ -216,7 +216,9 @@ def _find_torsions(root, atoms): for a1 in selected_atoms: # Find a0, which is a new atom connected to the selected atom a0_list = _sort_atoms_by_mass( - a for a in a1.bonded_atoms if (a in atoms) and (a not in selected_atoms) + a + for a in a1.bonded_atoms + if (a in atoms) and (a not in selected_atoms) ) for a0 in a0_list: # Find a2, which is connected to a1, is not a terminal atom, @@ -379,7 +381,9 @@ def __init__(self, ag, initial_atom=None, filename=None, **kwargs): self._primary_torsion_indices = [ prior_atoms.index(prior_atoms[n]) for n in range(len(prior_atoms)) ] - self._unique_primary_torsion_indices = list(set(self._primary_torsion_indices)) + self._unique_primary_torsion_indices = list( + set(self._primary_torsion_indices) + ) self._ag1 = mda.AtomGroup([ag[0] for ag in self._torsions]) self._ag2 = mda.AtomGroup([ag[1] for ag in self._torsions]) @@ -418,7 +422,8 @@ def _single_frame(self): 1.0, np.einsum("i,i->", v01, v21) / np.sqrt( - np.einsum("i,i->", v01, v01) * np.einsum("i,i->", v21, v21) + np.einsum("i,i->", v01, v01) + * np.einsum("i,i->", v21, v21) ), ), ) @@ -432,7 +437,9 @@ def _single_frame(self): sp = np.sin(phi) ct = np.cos(theta) st = np.sin(theta) - Rz = np.array([[cp * ct, ct * sp, -st], [-sp, cp, 0], [cp * st, sp * st, ct]]) + Rz = np.array( + [[cp * ct, ct * sp, -st], [-sp, cp, 0], [cp * st, sp * st, ct]] + ) pos2 = Rz.dot(p2 - p1) # Angle about the rotation axis omega = np.arctan2(pos2[1], pos2[0]) @@ -569,7 +576,9 @@ def Cartesian(self, bat_frame): ct = np.cos(theta) st = np.sin(theta) # $R_Z(\phi) R_Y(\theta)$ - Re = np.array([[cp * ct, -sp, cp * st], [ct * sp, cp, sp * st], [-st, 0, ct]]) + Re = np.array( + [[cp * ct, -sp, cp * st], [ct * sp, cp, sp * st], [-st, 0, ct]] + ) p1 = Re.dot(p1) p2 = Re.dot(p2) # Translate the first three atoms by the origin diff --git a/package/MDAnalysis/analysis/contacts.py b/package/MDAnalysis/analysis/contacts.py index 9956967fac..5d63471ae7 100644 --- a/package/MDAnalysis/analysis/contacts.py +++ b/package/MDAnalysis/analysis/contacts.py @@ -451,7 +451,9 @@ def __init__( elif method == "soft_cut": self.fraction_contacts = soft_cut_q elif method == "radius_cut": - self.fraction_contacts = functools.partial(radius_cut_q, radius=radius) + self.fraction_contacts = functools.partial( + radius_cut_q, radius=radius + ) else: if not callable(method): raise ValueError("method has to be callable") @@ -490,7 +492,9 @@ def __init__( box=self._get_box(refA.universe), ) ) - self.initial_contacts.append(contact_matrix(self.r0[-1], radius)) + self.initial_contacts.append( + contact_matrix(self.r0[-1], radius) + ) self.n_initial_contacts = self.initial_contacts[0].sum() diff --git a/package/MDAnalysis/analysis/density.py b/package/MDAnalysis/analysis/density.py index aa4df1b9ce..61c4e67989 100644 --- a/package/MDAnalysis/analysis/density.py +++ b/package/MDAnalysis/analysis/density.py @@ -439,7 +439,9 @@ def __init__( # in _prepare(), which is executed in parallel on different # parts of the trajectory). coord = self._atomgroup.positions - if self._gridcenter is not None or any([self._xdim, self._ydim, self._zdim]): + if self._gridcenter is not None or any( + [self._xdim, self._ydim, self._zdim] + ): # Issue 2372: padding is ignored, defaults to 2.0 therefore warn if self._padding > 0: msg = ( @@ -802,17 +804,24 @@ def _check_set_unit(self, u): # all this unit crap should be a class... try: for unit_type, value in u.items(): - if value is None: # check here, too iffy to use dictionary[None]=None + if ( + value is None + ): # check here, too iffy to use dictionary[None]=None self.units[unit_type] = None continue try: units.conversion_factor[unit_type][value] self.units[unit_type] = value except KeyError: - errmsg = f"Unit {value} of type {unit_type} is not " f"recognized." + errmsg = ( + f"Unit {value} of type {unit_type} is not " + f"recognized." + ) raise ValueError(errmsg) from None except AttributeError: - errmsg = '"unit" must be a dictionary with keys "length" and "density.' + errmsg = ( + '"unit" must be a dictionary with keys "length" and "density.' + ) logger.fatal(errmsg) raise ValueError(errmsg) from None # need at least length and density (can be None) @@ -869,7 +878,9 @@ def convert_length(self, unit="Angstrom"): """ if unit == self.units["length"]: return - cvnfact = units.get_conversion_factor("length", self.units["length"], unit) + cvnfact = units.get_conversion_factor( + "length", self.units["length"], unit + ) self.edges = [x * cvnfact for x in self.edges] self.units["length"] = unit self._update() # needed to recalculate midpoints and origin @@ -936,4 +947,10 @@ def __repr__(self): grid_type = "density" else: grid_type = "histogram" - return "" + return ( + "" + ) diff --git a/package/MDAnalysis/analysis/diffusionmap.py b/package/MDAnalysis/analysis/diffusionmap.py index 3817835ddd..65330196ec 100644 --- a/package/MDAnalysis/analysis/diffusionmap.py +++ b/package/MDAnalysis/analysis/diffusionmap.py @@ -235,25 +235,16 @@ class DistanceMatrix(AnalysisBase): :class:`DistanceMatrix` is now correctly works with `frames=...` parameter (#4432) by iterating over `self._sliced_trajectory` """ - - def __init__( - self, - universe, - select="all", - metric=rmsd, - cutoff=1e0 - 5, - weights=None, - **kwargs - ): + def __init__(self, universe, select='all', metric=rmsd, cutoff=1E0-5, + weights=None, **kwargs): # remember that this must be called before referencing self.n_frames - super(DistanceMatrix, self).__init__(universe.universe.trajectory, **kwargs) + super(DistanceMatrix, self).__init__(universe.universe.trajectory, + **kwargs) if isinstance(universe, UpdatingAtomGroup): - wmsg = ( - "U must be a static AtomGroup. Parsing an updating AtomGroup " - "will result in a static AtomGroup with the current frame " - "atom selection." - ) + wmsg = ("U must be a static AtomGroup. Parsing an updating AtomGroup " + "will result in a static AtomGroup with the current frame " + "atom selection.") warnings.warn(wmsg) self.atoms = universe.select_atoms(select) @@ -275,21 +266,20 @@ def _single_frame(self): self._ts = ts j_ref = self.atoms.positions dist = self._metric(i_ref, j_ref, weights=self._weights) - self.results.dist_matrix[self._frame_index, j + self._frame_index] = ( - dist if dist > self._cutoff else 0 - ) - self.results.dist_matrix[j + self._frame_index, self._frame_index] = ( - self.results.dist_matrix[self._frame_index, j + self._frame_index] - ) + self.results.dist_matrix[self._frame_index, + j+self._frame_index] = ( + dist if dist > self._cutoff else 0) + self.results.dist_matrix[j+self._frame_index, + self._frame_index] = ( + self.results.dist_matrix[self._frame_index, + j+self._frame_index]) self._ts = self._sliced_trajectory[iframe] @property def dist_matrix(self): - wmsg = ( - "The `dist_matrix` attribute was deprecated in " - "MDAnalysis 2.0.0 and will be removed in MDAnalysis 3.0.0. " - "Please use `results.dist_matrix` instead." - ) + wmsg = ("The `dist_matrix` attribute was deprecated in " + "MDAnalysis 2.0.0 and will be removed in MDAnalysis 3.0.0. " + "Please use `results.dist_matrix` instead.") warnings.warn(wmsg, DeprecationWarning) return self.results.dist_matrix @@ -344,14 +334,12 @@ def __init__(self, u, epsilon=1, **kwargs): elif isinstance(u, DistanceMatrix): self._dist_matrix = u else: - raise ValueError( - "U is not a Universe or AtomGroup or DistanceMatrix and" - " so the DiffusionMap has no data to work with." - ) + raise ValueError("U is not a Universe or AtomGroup or DistanceMatrix and" + " so the DiffusionMap has no data to work with.") self._epsilon = epsilon def run(self, start=None, stop=None, step=None): - """Create and decompose the diffusion matrix in preparation + """ Create and decompose the diffusion matrix in preparation for a diffusion map. Parameters @@ -372,12 +360,11 @@ def run(self, start=None, stop=None, step=None): # important for transform function and length of .run() method self._n_frames = self._dist_matrix.n_frames if self._n_frames > 5000: - warnings.warn( - "The distance matrix is very large, and can " - "be very slow to compute. Consider picking a larger " - "step size in distance matrix initialization." - ) - self._scaled_matrix = self._dist_matrix.results.dist_matrix**2 / self._epsilon + warnings.warn("The distance matrix is very large, and can " + "be very slow to compute. Consider picking a larger " + "step size in distance matrix initialization.") + self._scaled_matrix = (self._dist_matrix.results.dist_matrix ** 2 / + self._epsilon) # take negative exponent of scaled matrix to create Isotropic kernel self._kernel = np.exp(-self._scaled_matrix) D_inv = np.diag(1 / self._kernel.sum(1)) @@ -390,7 +377,7 @@ def run(self, start=None, stop=None, step=None): return self def transform(self, n_eigenvectors, time): - """Embeds a trajectory via the diffusion map + """ Embeds a trajectory via the diffusion map Parameters --------- @@ -405,6 +392,5 @@ def transform(self, n_eigenvectors, time): diffusion_space : array (n_frames, n_eigenvectors) The diffusion map embedding as defined by :footcite:p:`Ferguson2011`. """ - return self._eigenvectors[1 : n_eigenvectors + 1,].T * ( - self.eigenvalues[1 : n_eigenvectors + 1] ** time - ) + return (self._eigenvectors[1:n_eigenvectors+1,].T * + (self.eigenvalues[1:n_eigenvectors+1]**time)) diff --git a/package/MDAnalysis/analysis/dihedrals.py b/package/MDAnalysis/analysis/dihedrals.py index 9eaa3ba9cb..0c5ecb33cd 100644 --- a/package/MDAnalysis/analysis/dihedrals.py +++ b/package/MDAnalysis/analysis/dihedrals.py @@ -295,7 +295,9 @@ def __init__(self, atomgroups, **kwargs): If any atomgroups do not contain 4 atoms """ - super(Dihedral, self).__init__(atomgroups[0].universe.trajectory, **kwargs) + super(Dihedral, self).__init__( + atomgroups[0].universe.trajectory, **kwargs + ) self.atomgroups = atomgroups if any([len(ag) != 4 for ag in atomgroups]): @@ -423,7 +425,9 @@ def __init__( check_protein=True, **kwargs, ): - super(Ramachandran, self).__init__(atomgroup.universe.trajectory, **kwargs) + super(Ramachandran, self).__init__( + atomgroup.universe.trajectory, **kwargs + ) self.atomgroup = atomgroup residues = self.atomgroup.residues @@ -450,7 +454,8 @@ def __init__( if not np.all(keep): warnings.warn( - "Some residues in selection do not have " "phi or psi selections" + "Some residues in selection do not have " + "phi or psi selections" ) prev = sum(prev[keep]) nxt = sum(nxt[keep]) @@ -459,7 +464,9 @@ def __init__( # find n, c, ca keep_prev = [sum(r.atoms.names == c_name) == 1 for r in prev] rnames = [n_name, c_name, ca_name] - keep_res = [all(sum(r.atoms.names == n) == 1 for n in rnames) for r in residues] + keep_res = [ + all(sum(r.atoms.names == n) == 1 for n in rnames) for r in residues + ] keep_next = [sum(r.atoms.names == n_name) == 1 for r in nxt] # alright we'll keep these @@ -538,16 +545,22 @@ def plot(self, ax=None, ref=False, **kwargs): xlabel=r"$\phi$", ylabel=r"$\psi$", ) - degree_formatter = plt.matplotlib.ticker.StrMethodFormatter(r"{x:g}$\degree$") + degree_formatter = plt.matplotlib.ticker.StrMethodFormatter( + r"{x:g}$\degree$" + ) ax.xaxis.set_major_formatter(degree_formatter) ax.yaxis.set_major_formatter(degree_formatter) if ref: - X, Y = np.meshgrid(np.arange(-180, 180, 4), np.arange(-180, 180, 4)) + X, Y = np.meshgrid( + np.arange(-180, 180, 4), np.arange(-180, 180, 4) + ) levels = [1, 17, 15000] colors = ["#A1D4FF", "#35A1FF"] ax.contourf(X, Y, np.load(Rama_ref), levels=levels, colors=colors) - a = self.results.angles.reshape(np.prod(self.results.angles.shape[:2]), 2) + a = self.results.angles.reshape( + np.prod(self.results.angles.shape[:2]), 2 + ) ax.scatter(a[:, 0], a[:, 1], **kwargs) return ax @@ -624,7 +637,9 @@ def __init__( :attr:`angles` results are now stored in a :class:`MDAnalysis.analysis.base.Results` instance. """ - super(Ramachandran, self).__init__(atomgroup.universe.trajectory, **kwargs) + super(Ramachandran, self).__init__( + atomgroup.universe.trajectory, **kwargs + ) self.atomgroup = atomgroup residues = atomgroup.residues protein = atomgroup.select_atoms(select_protein).residues @@ -654,7 +669,8 @@ def __init__( # must be removed before using the class, or the file is missing atoms # for some residues which must also be removed if any( - len(self.ag1) != len(ag) for ag in [self.ag2, self.ag3, self.ag4, self.ag5] + len(self.ag1) != len(ag) + for ag in [self.ag2, self.ag3, self.ag4, self.ag5] ): raise ValueError( "Too many or too few atoms selected. Check for " @@ -662,7 +678,9 @@ def __init__( ) def _conclude(self): - self.results.angles = (np.rad2deg(np.array(self.results.angles)) + 360) % 360 + self.results.angles = ( + np.rad2deg(np.array(self.results.angles)) + 360 + ) % 360 def plot(self, ax=None, ref=False, **kwargs): """Plots data into standard Janin plot. @@ -700,7 +718,9 @@ def plot(self, ax=None, ref=False, **kwargs): xlabel=r"$\chi_1$", ylabel=r"$\chi_2$", ) - degree_formatter = plt.matplotlib.ticker.StrMethodFormatter(r"{x:g}$\degree$") + degree_formatter = plt.matplotlib.ticker.StrMethodFormatter( + r"{x:g}$\degree$" + ) ax.xaxis.set_major_formatter(degree_formatter) ax.yaxis.set_major_formatter(degree_formatter) @@ -709,6 +729,8 @@ def plot(self, ax=None, ref=False, **kwargs): levels = [1, 6, 600] colors = ["#A1D4FF", "#35A1FF"] ax.contourf(X, Y, np.load(Janin_ref), levels=levels, colors=colors) - a = self.results.angles.reshape(np.prod(self.results.angles.shape[:2]), 2) + a = self.results.angles.reshape( + np.prod(self.results.angles.shape[:2]), 2 + ) ax.scatter(a[:, 0], a[:, 1], **kwargs) return ax diff --git a/package/MDAnalysis/analysis/distances.py b/package/MDAnalysis/analysis/distances.py index 604ab53f6b..44a09c4fcb 100644 --- a/package/MDAnalysis/analysis/distances.py +++ b/package/MDAnalysis/analysis/distances.py @@ -168,7 +168,9 @@ def dist(A, B, offset=0, box=None): """ if A.atoms.n_atoms != B.atoms.n_atoms: - raise ValueError("AtomGroups A and B do not have the same number of atoms") + raise ValueError( + "AtomGroups A and B do not have the same number of atoms" + ) try: off_A, off_B = offset except (TypeError, ValueError): diff --git a/package/MDAnalysis/analysis/dssp/dssp.py b/package/MDAnalysis/analysis/dssp/dssp.py index b1aef1bd0a..d88f1bdbe4 100644 --- a/package/MDAnalysis/analysis/dssp/dssp.py +++ b/package/MDAnalysis/analysis/dssp/dssp.py @@ -316,7 +316,8 @@ def __init__( for t in heavyatom_names } self._hydrogens: list["AtomGroup"] = [ - res.atoms.select_atoms(f"name {hydrogen_name}") for res in ag.residues + res.atoms.select_atoms(f"name {hydrogen_name}") + for res in ag.residues ] # can't do it the other way because I need missing values to exist # so that I could fill them in later @@ -372,7 +373,9 @@ def _get_coords(self) -> np.ndarray: coords = np.array(positions) if not self._guess_hydrogens: - guessed_h_coords = _get_hydrogen_atom_position(coords.swapaxes(0, 1)) + guessed_h_coords = _get_hydrogen_atom_position( + coords.swapaxes(0, 1) + ) h_coords = np.array( [ diff --git a/package/MDAnalysis/analysis/dssp/pydssp_numpy.py b/package/MDAnalysis/analysis/dssp/pydssp_numpy.py index 1ae8ac369e..f54ea5443a 100644 --- a/package/MDAnalysis/analysis/dssp/pydssp_numpy.py +++ b/package/MDAnalysis/analysis/dssp/pydssp_numpy.py @@ -65,7 +65,10 @@ def _upsample(a: np.ndarray, window: int) -> np.ndarray: def _unfold(a: np.ndarray, window: int, axis: int): "Helper function for 2D array upsampling" - idx = np.arange(window)[:, None] + np.arange(a.shape[axis] - window + 1)[None, :] + idx = ( + np.arange(window)[:, None] + + np.arange(a.shape[axis] - window + 1)[None, :] + ) unfolded = np.take(a, idx, axis=axis) return np.moveaxis(unfolded, axis - 1, -1) @@ -154,7 +157,9 @@ def get_hbond_map( h_1 = coord[1:, 4] coord = coord[:, :4] else: # pragma: no cover - raise ValueError("Number of atoms should be 4 (N,CA,C,O) or 5 (N,CA,C,O,H)") + raise ValueError( + "Number of atoms should be 4 (N,CA,C,O) or 5 (N,CA,C,O,H)" + ) # after this: # h.shape == (n_atoms, 3) # coord.shape == (n_atoms, 4, 3) @@ -176,7 +181,9 @@ def get_hbond_map( # electrostatic interaction energy # e[i, j] = e(CO_i) - e(NH_j) e = np.pad( - CONST_Q1Q2 * (1.0 / d_on + 1.0 / d_ch - 1.0 / d_oh - 1.0 / d_cn) * CONST_F, + CONST_Q1Q2 + * (1.0 / d_on + 1.0 / d_ch - 1.0 / d_oh - 1.0 / d_cn) + * CONST_F, [[1, 0], [0, 1]], ) diff --git a/package/MDAnalysis/analysis/encore/bootstrap.py b/package/MDAnalysis/analysis/encore/bootstrap.py index 48bdf8c98c..8784409c7f 100644 --- a/package/MDAnalysis/analysis/encore/bootstrap.py +++ b/package/MDAnalysis/analysis/encore/bootstrap.py @@ -116,7 +116,9 @@ def get_distance_matrix_bootstrap_samples( confdistmatrix : list of encore.utils.TriangularMatrix """ - bs_args = [([distance_matrix, ensemble_assignment]) for i in range(samples)] + bs_args = [ + ([distance_matrix, ensemble_assignment]) for i in range(samples) + ] pc = ParallelCalculation(ncores, bootstrapped_matrix, bs_args) diff --git a/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py b/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py index cde3cbff95..8c545c5421 100644 --- a/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py +++ b/package/MDAnalysis/analysis/encore/clustering/ClusterCollection.py @@ -99,7 +99,9 @@ def __init__(self, elem_list=None, centroid=None, idn=None, metadata=None): self.metadata = {} self.elements = elem_list if centroid not in self.elements: - raise LookupError("Centroid of cluster not found in the element list") + raise LookupError( + "Centroid of cluster not found in the element list" + ) self.centroid = centroid self.size = self.elements.shape[0] @@ -128,7 +130,8 @@ def __len__(self): def add_metadata(self, name, data): if len(data) != self.size: raise TypeError( - "Size of metadata is not equal to the number of " "cluster elements" + "Size of metadata is not equal to the number of " + "cluster elements" ) self.metadata[name] = np.array(data) @@ -267,4 +270,6 @@ def __repr__(self): if self.clusters is None: return "" else: - return "".format(len(self.clusters)) + return "".format( + len(self.clusters) + ) diff --git a/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py b/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py index 8aff6e3815..9af8d48fa8 100644 --- a/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py +++ b/package/MDAnalysis/analysis/encore/clustering/ClusteringMethod.py @@ -96,7 +96,9 @@ def __call__(self, x): """ raise NotImplementedError( - "Class {0} doesn't implement __call__()".format(self.__class__.__name__) + "Class {0} doesn't implement __call__()".format( + self.__class__.__name__ + ) ) @@ -245,13 +247,17 @@ def __call__(self, distance_matrix): This method no longer returns ``details`` """ logging.info( - "Starting Affinity Propagation: {0}".format(self.ap.get_params()) + "Starting Affinity Propagation: {0}".format( + self.ap.get_params() + ) ) # Convert from distance matrix to similarity matrix similarity_matrix = distance_matrix.as_array() * -1 clusters = self.ap.fit_predict(similarity_matrix) - clusters = encode_centroid_info(clusters, self.ap.cluster_centers_indices_) + clusters = encode_centroid_info( + clusters, self.ap.cluster_centers_indices_ + ) return clusters @@ -326,7 +332,9 @@ def __call__(self, distance_matrix): .. versionchanged:: 1.0.0 This method no longer returns ``details`` """ - logging.info("Starting DBSCAN: {0}".format(self.dbscan.get_params())) + logging.info( + "Starting DBSCAN: {0}".format(self.dbscan.get_params()) + ) clusters = self.dbscan.fit_predict(distance_matrix.as_array()) if np.min(clusters == -1): clusters += 1 @@ -436,7 +444,9 @@ def __call__(self, coordinates): .. versionchanged:: 1.0.0 This method no longer returns ``details`` """ - logging.info("Starting Kmeans: {0}".format((self.kmeans.get_params()))) + logging.info( + "Starting Kmeans: {0}".format((self.kmeans.get_params())) + ) clusters = self.kmeans.fit_predict(coordinates) distances = self.kmeans.transform(coordinates) cluster_center_indices = np.argmin(distances, axis=0) diff --git a/package/MDAnalysis/analysis/encore/clustering/cluster.py b/package/MDAnalysis/analysis/encore/clustering/cluster.py index 2aba87e3ef..2173a8d207 100644 --- a/package/MDAnalysis/analysis/encore/clustering/cluster.py +++ b/package/MDAnalysis/analysis/encore/clustering/cluster.py @@ -190,7 +190,9 @@ def cluster( if distance_matrix: if not hasattr(distance_matrix, "__iter__"): distance_matrix = [distance_matrix] - if ensembles is not None and len(distance_matrix) != len(merged_ensembles): + if ensembles is not None and len(distance_matrix) != len( + merged_ensembles + ): raise ValueError( "Dimensions of provided list of distance matrices " "does not match that of provided list of " @@ -205,7 +207,9 @@ def cluster( distance_matrix = [] for merged_ensemble in merged_ensembles: distance_matrix.append( - get_distance_matrix(merged_ensemble, select=select, **kwargs) + get_distance_matrix( + merged_ensemble, select=select, **kwargs + ) ) args = [] @@ -214,10 +218,14 @@ def cluster( args += [(d,) for d in distance_matrix] else: for merged_ensemble in merged_ensembles: - coordinates = merged_ensemble.trajectory.timeseries(order="fac") + coordinates = merged_ensemble.trajectory.timeseries( + order="fac" + ) # Flatten coordinate matrix into n_frame x n_coordinates - coordinates = np.reshape(coordinates, (coordinates.shape[0], -1)) + coordinates = np.reshape( + coordinates, (coordinates.shape[0], -1) + ) args.append((coordinates,)) @@ -238,7 +246,10 @@ def cluster( # Create clusters collections from clustering results, # one for each cluster. None if clustering didn't work. - ccs = [ClusterCollection(clusters[1], metadata=metadata) for clusters in results] + ccs = [ + ClusterCollection(clusters[1], metadata=metadata) + for clusters in results + ] if allow_collapsed_result and len(ccs) == 1: ccs = ccs[0] diff --git a/package/MDAnalysis/analysis/encore/confdistmatrix.py b/package/MDAnalysis/analysis/encore/confdistmatrix.py index 6156aa2cc9..95b22bf056 100644 --- a/package/MDAnalysis/analysis/encore/confdistmatrix.py +++ b/package/MDAnalysis/analysis/encore/confdistmatrix.py @@ -112,7 +112,9 @@ def conformational_distance_matrix( # framesn: number of frames framesn = len( - ensemble.trajectory.timeseries(ensemble.select_atoms(select), order="fac") + ensemble.trajectory.timeseries( + ensemble.select_atoms(select), order="fac" + ) ) # Prepare metadata recarray @@ -160,20 +162,29 @@ def conformational_distance_matrix( else: fitting_coordinates = None - if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": + if ( + not isinstance(weights, (list, tuple, np.ndarray)) + and weights == "mass" + ): weights = ensemble.select_atoms(select).masses.astype(np.float64) if pairwise_align: - subset_weights = ensemble.select_atoms(subset_select).masses.astype( - np.float64 - ) + subset_weights = ensemble.select_atoms( + subset_select + ).masses.astype(np.float64) else: subset_weights = None elif weights is None: weights = np.ones( - (ensemble.trajectory.timeseries(ensemble.select_atoms(select))[0].shape[0]) + ( + ensemble.trajectory.timeseries(ensemble.select_atoms(select))[ + 0 + ].shape[0] + ) ).astype(np.float64) if pairwise_align: - subset_weights = np.ones((fit_coords[0].shape[0])).astype(np.float64) + subset_weights = np.ones((fit_coords[0].shape[0])).astype( + np.float64 + ) else: subset_weights = None else: @@ -280,7 +291,9 @@ def set_rmsd_matrix_elements( com_j = np.average(fit_coords[j], axis=0, weights=fit_weights) translated_j = coords[j] - com_j subset2_coords = fit_coords[j] - com_j - rotamat = rotation_matrix(subset1_coords, subset2_coords, subset_weights)[0] + rotamat = rotation_matrix( + subset1_coords, subset2_coords, subset_weights + )[0] rotated_i = np.transpose(np.dot(rotamat, np.transpose(translated_i))) rmsdmat[(i + 1) * i // 2 + j] = PureRMSD( rotated_i.astype(np.float64), @@ -362,7 +375,9 @@ def get_distance_matrix( # Load the matrix if required if load_matrix: - logging.info(" Loading similarity matrix from: {0}".format(load_matrix)) + logging.info( + " Loading similarity matrix from: {0}".format(load_matrix) + ) confdistmatrix = TriangularMatrix( size=ensemble.trajectory.timeseries( ensemble.select_atoms(select), order="fac" @@ -372,7 +387,9 @@ def get_distance_matrix( logging.info(" Done!") for key in confdistmatrix.metadata.dtype.names: logging.info( - " {0} : {1}".format(key, str(confdistmatrix.metadata[key][0])) + " {0} : {1}".format( + key, str(confdistmatrix.metadata[key][0]) + ) ) # Check matrix size for consistency @@ -394,17 +411,26 @@ def get_distance_matrix( # Transfer universe to memory to ensure timeseries() support ensemble.transfer_to_memory() - if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": + if ( + not isinstance(weights, (list, tuple, np.ndarray)) + and weights == "mass" + ): weight_type = "Mass" elif weights is None: weight_type = "None" else: weight_type = "Custom" - logging.info(" Perform pairwise alignment: {0}".format(str(superimpose))) - logging.info(" weighted alignment and RMSD: {0}".format(weight_type)) + logging.info( + " Perform pairwise alignment: {0}".format(str(superimpose)) + ) + logging.info( + " weighted alignment and RMSD: {0}".format(weight_type) + ) if superimpose: logging.info( - " Atoms subset for alignment: {0}".format(superimposition_subset) + " Atoms subset for alignment: {0}".format( + superimposition_subset + ) ) logging.info(" Calculating similarity matrix . . .") diff --git a/package/MDAnalysis/analysis/encore/covariance.py b/package/MDAnalysis/analysis/encore/covariance.py index 727706f5dd..08e014e315 100644 --- a/package/MDAnalysis/analysis/encore/covariance.py +++ b/package/MDAnalysis/analysis/encore/covariance.py @@ -151,14 +151,18 @@ def shrinkage_covariance_estimator( p = 1 / float(t) * np.sum(np.dot(np.transpose(y), y)) - np.sum( np.sum(sample**2) ) - rdiag = 1 / float(t) * np.sum(np.sum(y**2)) - np.sum(np.diag(sample) ** 2) + rdiag = 1 / float(t) * np.sum(np.sum(y**2)) - np.sum( + np.diag(sample) ** 2 + ) z = x * np.repeat(xmkt[:, np.newaxis], n, axis=1) v1 = ( 1 / float(t) * np.dot(np.transpose(y), z) - np.repeat(covmkt[:, np.newaxis], n, axis=1) * sample ) roff1 = ( - np.sum(v1 * np.transpose(np.repeat(covmkt[:, np.newaxis], n, axis=1))) + np.sum( + v1 * np.transpose(np.repeat(covmkt[:, np.newaxis], n, axis=1)) + ) / varmkt - np.sum(np.diag(v1) * covmkt) / varmkt ) @@ -236,7 +240,10 @@ def covariance_matrix( # Optionally correct with weights if weights is not None: # Calculate mass-weighted covariance matrix - if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": + if ( + not isinstance(weights, (list, tuple, np.ndarray)) + and weights == "mass" + ): if select: weights = ensemble.select_atoms(select).masses else: @@ -248,7 +255,8 @@ def covariance_matrix( req_len = ensemble.atoms.n_atoms if req_len != len(weights): raise ValueError( - "number of weights is unequal to number of " "atoms in ensemble" + "number of weights is unequal to number of " + "atoms in ensemble" ) # broadcast to a (len(weights), 3) array diff --git a/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py b/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py index 4005e59673..3ca43202f5 100644 --- a/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py +++ b/package/MDAnalysis/analysis/encore/dimensionality_reduction/DimensionalityReductionMethod.py @@ -85,7 +85,9 @@ def __call__(self, x): """ raise NotImplementedError( - "Class {0} doesn't implement __call__()".format(self.__class__.__name__) + "Class {0} doesn't implement __call__()".format( + self.__class__.__name__ + ) ) @@ -148,15 +150,17 @@ def __call__(self, distance_matrix): coordinates in reduced space """ - final_stress, coordinates = stochasticproxembed.StochasticProximityEmbedding( - s=distance_matrix, - rco=self.distance_cutoff, - dim=self.dimension, - minlam=self.min_lam, - maxlam=self.max_lam, - ncycle=self.ncycle, - nstep=self.nstep, - stressfreq=self.stressfreq, + final_stress, coordinates = ( + stochasticproxembed.StochasticProximityEmbedding( + s=distance_matrix, + rco=self.distance_cutoff, + dim=self.dimension, + minlam=self.min_lam, + maxlam=self.max_lam, + ncycle=self.ncycle, + nstep=self.nstep, + stressfreq=self.stressfreq, + ) ) return coordinates, {"final_stress": final_stress} @@ -181,7 +185,9 @@ def __init__(self, dimension=2, **kwargs): Number of dimensions to which the conformational space will be reduced to (default is 3). """ - self.pca = sklearn.decomposition.PCA(n_components=dimension, **kwargs) + self.pca = sklearn.decomposition.PCA( + n_components=dimension, **kwargs + ) def __call__(self, coordinates): """ diff --git a/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py b/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py index 26315fdf40..d1e05e1cd2 100644 --- a/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py +++ b/package/MDAnalysis/analysis/encore/dimensionality_reduction/reduce_dimensionality.py @@ -187,7 +187,9 @@ def reduce_dimensionality( if distance_matrix: if not hasattr(distance_matrix, "__iter__"): distance_matrix = [distance_matrix] - if ensembles is not None and len(distance_matrix) != len(merged_ensembles): + if ensembles is not None and len(distance_matrix) != len( + merged_ensembles + ): raise ValueError( "Dimensions of provided list of distance matrices " "does not match that of provided list of " @@ -202,7 +204,9 @@ def reduce_dimensionality( distance_matrix = [] for merged_ensemble in merged_ensembles: distance_matrix.append( - get_distance_matrix(merged_ensemble, select=select, **kwargs) + get_distance_matrix( + merged_ensemble, select=select, **kwargs + ) ) args = [] @@ -211,10 +215,14 @@ def reduce_dimensionality( args += [(d,) for d in distance_matrix] else: for merged_ensemble in merged_ensembles: - coordinates = merged_ensemble.trajectory.timeseries(order="fac") + coordinates = merged_ensemble.trajectory.timeseries( + order="fac" + ) # Flatten coordinate matrix into n_frame x n_coordinates - coordinates = np.reshape(coordinates, (coordinates.shape[0], -1)) + coordinates = np.reshape( + coordinates, (coordinates.shape[0], -1) + ) args.append((coordinates,)) diff --git a/package/MDAnalysis/analysis/encore/similarity.py b/package/MDAnalysis/analysis/encore/similarity.py index d1abbded74..17b9fb2886 100644 --- a/package/MDAnalysis/analysis/encore/similarity.py +++ b/package/MDAnalysis/analysis/encore/similarity.py @@ -302,12 +302,15 @@ def harmonic_ensemble_similarity(sigma1, sigma2, x1, x2): ) d_hes = 0.25 * ( - np.dot(np.transpose(d_avg), np.dot(sigma1_inv + sigma2_inv, d_avg)) + trace + np.dot(np.transpose(d_avg), np.dot(sigma1_inv + sigma2_inv, d_avg)) + + trace ) return d_hes -def clustering_ensemble_similarity(cc, ens1, ens1_id, ens2, ens2_id, select="name CA"): +def clustering_ensemble_similarity( + cc, ens1, ens1_id, ens2, ens2_id, select="name CA" +): """Clustering ensemble similarity: calculate the probability densities from the clusters and calculate discrete Jensen-Shannon divergence. @@ -588,13 +591,19 @@ def dimred_ensemble_similarity( ln_P1_exp_P1 = np.average(np.log(kde1.evaluate(resamples1))) ln_P2_exp_P2 = np.average(np.log(kde2.evaluate(resamples2))) ln_P1P2_exp_P1 = np.average( - np.log(0.5 * (kde1.evaluate(resamples1) + kde2.evaluate(resamples1))) + np.log( + 0.5 * (kde1.evaluate(resamples1) + kde2.evaluate(resamples1)) + ) ) ln_P1P2_exp_P2 = np.average( - np.log(0.5 * (kde1.evaluate(resamples2) + kde2.evaluate(resamples2))) + np.log( + 0.5 * (kde1.evaluate(resamples2) + kde2.evaluate(resamples2)) + ) ) - return 0.5 * (ln_P1_exp_P1 - ln_P1P2_exp_P1 + ln_P2_exp_P2 - ln_P1P2_exp_P2) + return 0.5 * ( + ln_P1_exp_P1 - ln_P1P2_exp_P1 + ln_P2_exp_P2 - ln_P1P2_exp_P2 + ) def cumulative_gen_kde_pdfs( @@ -681,7 +690,9 @@ def cumulative_gen_kde_pdfs( return (kdes, resamples, embedded_ensembles) -def write_output(matrix, base_fname=None, header="", suffix="", extension="dat"): +def write_output( + matrix, base_fname=None, header="", suffix="", extension="dat" +): """ Write output matrix with a nice format, to stdout and optionally a file. @@ -894,7 +905,10 @@ def hes( """ - if not isinstance(weights, (list, tuple, np.ndarray)) and weights == "mass": + if ( + not isinstance(weights, (list, tuple, np.ndarray)) + and weights == "mass" + ): weights = ["mass" for _ in range(len(ensembles))] elif weights is not None: if len(weights) != len(ensembles): @@ -943,7 +957,9 @@ def hes( ensembles_list = [] for i, ensemble in enumerate(ensembles): ensembles_list.append( - get_ensemble_bootstrap_samples(ensemble, samples=bootstrapping_samples) + get_ensemble_bootstrap_samples( + ensemble, samples=bootstrapping_samples + ) ) for t in range(bootstrapping_samples): logging.info("The coordinates will be bootstrapped.") @@ -1238,7 +1254,9 @@ def ces( failed_runs += 1 k += 1 continue - values[i].append(np.zeros((len(ensembles[j]), len(ensembles[j])))) + values[i].append( + np.zeros((len(ensembles[j]), len(ensembles[j]))) + ) for pair in pairs_indices: # Calculate dJS @@ -1449,10 +1467,16 @@ def dres( dimensionality_reduction_methods = [dimensionality_reduction_method] any_method_accept_distance_matrix = np.any( - [method.accepts_distance_matrix for method in dimensionality_reduction_methods] + [ + method.accepts_distance_matrix + for method in dimensionality_reduction_methods + ] ) all_methods_accept_distance_matrix = np.all( - [method.accepts_distance_matrix for method in dimensionality_reduction_methods] + [ + method.accepts_distance_matrix + for method in dimensionality_reduction_methods + ] ) # Register which ensembles the samples belong to @@ -1484,7 +1508,8 @@ def dres( ensembles = [] for j in range(bootstrapping_samples): ensembles.append( - ensembles_list[i, j] for i in range(ensembles_list.shape[0]) + ensembles_list[i, j] + for i in range(ensembles_list.shape[0]) ) else: # if all methods accept distances matrices, duplicate @@ -1515,7 +1540,9 @@ def dres( values[i] = [] for j in range(bootstrapping_samples): - values[i].append(np.zeros((len(ensembles[j]), len(ensembles[j])))) + values[i].append( + np.zeros((len(ensembles[j]), len(ensembles[j]))) + ) kdes, resamples, embedded_ensembles = gen_kde_pdfs( coordinates[k], diff --git a/package/MDAnalysis/analysis/encore/utils.py b/package/MDAnalysis/analysis/encore/utils.py index 77bc7a4189..ae6407ddd1 100644 --- a/package/MDAnalysis/analysis/encore/utils.py +++ b/package/MDAnalysis/analysis/encore/utils.py @@ -128,7 +128,9 @@ def loadz(self, fname): raise TypeError self.metadata = loaded["metadata"] else: - if self.size * (self.size - 1) / 2 + self.size != len(loaded["elements"]): + if self.size * (self.size - 1) / 2 + self.size != len( + loaded["elements"] + ): raise TypeError self._elements = loaded["elements"] @@ -239,7 +241,9 @@ class description. if not hasattr(self.functions, "__iter__"): self.functions = [self.functions] * len(args) if len(self.functions) != len(args): - self.functions = self.functions[:] * (len(args) // len(self.functions)) + self.functions = self.functions[:] * ( + len(args) // len(self.functions) + ) # Arguments should be present if args is None: @@ -275,7 +279,9 @@ def worker(self, q, results): if i == "STOP": return - results.put((i, self.functions[i](*self.args[i], **self.kwargs[i]))) + results.put( + (i, self.functions[i](*self.args[i], **self.kwargs[i])) + ) def run(self): r""" diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index 93d10067a5..a767c5c578 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -169,7 +169,9 @@ def neighbour_generator(positions, cutoff): n_x = len(grid) n_y = len(grid[0]) n_z = len(grid[0][0]) - for cell_x, cell_y, cell_z in itertools.product(range(n_x), range(n_y), range(n_z)): + for cell_x, cell_y, cell_z in itertools.product( + range(n_x), range(n_y), range(n_z) + ): atoms = grid[cell_x][cell_y][cell_z] # collect all atoms in own cell and neighboring cell all_atoms = [] @@ -279,11 +281,15 @@ def __init__( self._timesteps = None # time for each frame self.ReportVector = ReportVector self.Bonus_groups = ( - [self.u.select_atoms(item) for item in Bonus_groups] if Bonus_groups else [] + [self.u.select_atoms(item) for item in Bonus_groups] + if Bonus_groups + else [] ) self.ca = self.u.select_atoms(self.select) - def _generate_output(self, w, v, outputobject, ReportVector=None, counter=0): + def _generate_output( + self, w, v, outputobject, ReportVector=None, counter=0 + ): """Appends time, eigenvalues and eigenvectors to results. This generates the output by adding eigenvalue and @@ -470,7 +476,9 @@ def generate_kirchoff(self): ): iresidue = residue_index_map[i_atom] jresidue = residue_index_map[j_atom] - contact = inv_sqrt_res_sizes[iresidue] * inv_sqrt_res_sizes[jresidue] + contact = ( + inv_sqrt_res_sizes[iresidue] * inv_sqrt_res_sizes[jresidue] + ) matrix[iresidue][jresidue] -= contact matrix[jresidue][iresidue] -= contact matrix[iresidue][iresidue] += contact diff --git a/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py b/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py index dd85f35e0d..3f80affc81 100644 --- a/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py +++ b/package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py @@ -62,12 +62,14 @@ hbond_autocorrel.find_hydrogen_donors, release="2.0.0", remove="3.0.0", - message="The function was moved to " "MDAnalysis.analysis.hbonds.hbond_autocorrel.", + message="The function was moved to " + "MDAnalysis.analysis.hbonds.hbond_autocorrel.", ) HydrogenBondAutoCorrel = deprecate( hbond_autocorrel.HydrogenBondAutoCorrel, release="2.0.0", remove="3.0.0", - message="The class was moved to " "MDAnalysis.analysis.hbonds.hbond_autocorrel.", + message="The class was moved to " + "MDAnalysis.analysis.hbonds.hbond_autocorrel.", ) diff --git a/package/MDAnalysis/analysis/helix_analysis.py b/package/MDAnalysis/analysis/helix_analysis.py index a8c48aa682..e0edf76370 100644 --- a/package/MDAnalysis/analysis/helix_analysis.py +++ b/package/MDAnalysis/analysis/helix_analysis.py @@ -176,7 +176,9 @@ def local_screw_angles(global_axis, ref_axis, helix_directions): # angles from projection to perp refs = np.array([perp, ortho]) # (2, 3) - norms = _, ortho_norm = np.outer(mdamath.pnorm(refs), mdamath.pnorm(proj_plane)) + norms = _, ortho_norm = np.outer( + mdamath.pnorm(refs), mdamath.pnorm(proj_plane) + ) cos = cos_perp, cos_ortho = np.matmul(refs, proj_plane.T) / norms to_perp, to_ortho = np.arccos(np.clip(cos, -1, 1)) # (2, n_vec) to_ortho[ortho_norm == 0] = 0 # ? @@ -289,7 +291,9 @@ def helix_analysis(positions, ref_axis=(0, 0, 1)): origins[-1] -= radii[-1] * local_helix_directions[-1] helix_axes = vector_of_best_fit(origins) - screw = local_screw_angles(helix_axes, np.asarray(ref_axis), local_helix_directions) + screw = local_screw_angles( + helix_axes, np.asarray(ref_axis), local_helix_directions + ) results = { "local_twists": local_twists, @@ -397,7 +401,9 @@ def __init__( flatten_single_helix=True, split_residue_sequences=True, ): - super(HELANAL, self).__init__(universe.universe.trajectory, verbose=verbose) + super(HELANAL, self).__init__( + universe.universe.trajectory, verbose=verbose + ) selections = util.asiterable(select) atomgroups = [universe.select_atoms(s) for s in selections] consecutive = [] @@ -461,7 +467,9 @@ def _prepare(self): self.results[key] = empty self.results.global_axis = [self._zeros_per_frame((3,)) for n in n_res] - self.results.all_bends = [self._zeros_per_frame((n - 3, n - 3)) for n in n_res] + self.results.all_bends = [ + self._zeros_per_frame((n - 3, n - 3)) for n in n_res + ] def _single_frame(self): _f = self._frame_index @@ -476,7 +484,9 @@ def _conclude(self): self.results.global_tilts = tilts = [] norm_ref = (self.ref_axis**2).sum() ** 0.5 for axes in self.results.global_axis: - cos = np.matmul(self.ref_axis, axes.T) / (mdamath.pnorm(axes) * norm_ref) + cos = np.matmul(self.ref_axis, axes.T) / ( + mdamath.pnorm(axes) * norm_ref + ) cos = np.clip(cos, -1.0, 1.0) tilts.append(np.rad2deg(np.arccos(cos))) diff --git a/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py b/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py index 04b4707d50..544bd6e4e1 100644 --- a/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py +++ b/package/MDAnalysis/analysis/hydrogenbonds/hbond_analysis.py @@ -255,12 +255,10 @@ logger = logging.getLogger(__name__) -due.cite( - Doi("10.1039/C9CP01532A"), - description="Hydrogen bond analysis implementation", - path="MDAnalysis.analysis.hydrogenbonds.hbond_analysis", - cite_module=True, -) +due.cite(Doi("10.1039/C9CP01532A"), + description="Hydrogen bond analysis implementation", + path="MDAnalysis.analysis.hydrogenbonds.hbond_analysis", + cite_module=True) del Doi @@ -274,29 +272,18 @@ class HydrogenBondAnalysis(AnalysisBase): @classmethod def get_supported_backends(cls): - return ( - "serial", - "multiprocessing", - "dask", - ) + return ('serial', 'multiprocessing', 'dask',) - def __init__( - self, - universe, - donors_sel=None, - hydrogens_sel=None, - acceptors_sel=None, - between=None, - d_h_cutoff=1.2, - d_a_cutoff=3.0, - d_h_a_angle_cutoff=150, - update_selections=True, - ): + def __init__(self, universe, + donors_sel=None, hydrogens_sel=None, acceptors_sel=None, + between=None, d_h_cutoff=1.2, + d_a_cutoff=3.0, d_h_a_angle_cutoff=150, + update_selections=True): """Set up atom selections and geometric criteria for finding hydrogen bonds in a Universe. Hydrogen bond selections with `donors_sel` , `hydrogens_sel`, and - `acceptors_sel` may be achieved with either a *resname*, atom *name* + `acceptors_sel` may be achieved with either a *resname*, atom *name* combination, or when those are absent, with atom *type* selections. Parameters @@ -353,7 +340,7 @@ def __init__( .. versionadded:: 2.0.0 Added `between` keyword .. versionchanged:: 2.4.0 - Added use of atom types in selection strings for hydrogen atoms, + Added use of atom types in selection strings for hydrogen atoms, bond donors, or bond acceptors .. versionchanged:: 2.8.0 Introduced :meth:`get_supported_backends` allowing for parallel execution on @@ -368,19 +355,14 @@ def __init__( self._trajectory = self.u.trajectory self._donors_sel = donors_sel.strip() if donors_sel is not None else donors_sel - self._hydrogens_sel = ( - hydrogens_sel.strip() if hydrogens_sel is not None else hydrogens_sel - ) - self._acceptors_sel = ( - acceptors_sel.strip() if acceptors_sel is not None else acceptors_sel - ) - - msg = ( - "{} is an empty selection string - no hydrogen bonds will " - "be found. This may be intended, but please check your " - "selection." - ) - for sel in ["donors_sel", "hydrogens_sel", "acceptors_sel"]: + self._hydrogens_sel = hydrogens_sel.strip() if hydrogens_sel is not None else hydrogens_sel + self._acceptors_sel = acceptors_sel.strip() if acceptors_sel is not None else acceptors_sel + + msg = ("{} is an empty selection string - no hydrogen bonds will " + "be found. This may be intended, but please check your " + "selection." + ) + for sel in ['donors_sel', 'hydrogens_sel', 'acceptors_sel']: val = getattr(self, sel) if isinstance(val, str) and not val: warnings.warn(msg.format(sel)) @@ -398,7 +380,7 @@ def __init__( between_ags.append( [ self.u.select_atoms(group1, updating=False), - self.u.select_atoms(group2, updating=False), + self.u.select_atoms(group2, updating=False) ] ) @@ -406,6 +388,7 @@ def __init__( else: self.between_ags = None + self.d_h_cutoff = d_h_cutoff self.d_a_cutoff = d_a_cutoff self.d_h_a_angle = d_h_a_angle_cutoff @@ -420,19 +403,23 @@ def __init__( self._hydrogens_sel = self.guess_hydrogens() # Select atom groups - self._acceptors = self.u.select_atoms( - self.acceptors_sel, updating=self.update_selections - ) + self._acceptors = self.u.select_atoms(self.acceptors_sel, + updating=self.update_selections) self._donors, self._hydrogens = self._get_dh_pairs() - def guess_hydrogens(self, select="all", max_mass=1.1, min_charge=0.3, min_mass=0.9): + def guess_hydrogens(self, + select='all', + max_mass=1.1, + min_charge=0.3, + min_mass=0.9 + ): """Guesses which hydrogen atoms should be used in the analysis. Parameters ---------- select: str (optional) - :ref:`Selection string ` for atom group - from which hydrogens will be identified. (e.g., ``(resname X and + :ref:`Selection string ` for atom group + from which hydrogens will be identified. (e.g., ``(resname X and name H1)`` or ``type 2``) max_mass: float (optional) The mass of a hydrogen atom must be less than this value. @@ -444,24 +431,24 @@ def guess_hydrogens(self, select="all", max_mass=1.1, min_charge=0.3, min_mass=0 Returns ------- potential_hydrogens: str - String containing the :attr:`resname` and :attr:`name` of all + String containing the :attr:`resname` and :attr:`name` of all hydrogen atoms potentially capable of forming hydrogen bonds. Notes ----- - Hydrogen selections may be achieved with either a resname, atom + Hydrogen selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. This function makes use of atomic masses and atomic charges to identify - which atoms are hydrogen atoms that are capable of participating in - hydrogen bonding. If an atom has a mass less than :attr:`max_mass` and - an atomic charge greater than :attr:`min_charge` then it is considered + which atoms are hydrogen atoms that are capable of participating in + hydrogen bonding. If an atom has a mass less than :attr:`max_mass` and + an atomic charge greater than :attr:`min_charge` then it is considered capable of participating in hydrogen bonds. - If :attr:`hydrogens_sel` is `None`, this function is called to guess + If :attr:`hydrogens_sel` is `None`, this function is called to guess the selection. - Alternatively, this function may be used to quickly generate a + Alternatively, this function may be used to quickly generate a :class:`str` of potential hydrogen atoms involved in hydrogen bonding. This str may then be modified before being used to set the attribute :attr:`hydrogens_sel`. @@ -477,27 +464,25 @@ def guess_hydrogens(self, select="all", max_mass=1.1, min_charge=0.3, min_mass=0 ag = self.u.select_atoms(select) hydrogens_ag = ag[ - np.logical_and.reduce( - ( - ag.masses < max_mass, - ag.charges > min_charge, - ag.masses > min_mass, - ) - ) + np.logical_and.reduce(( + ag.masses < max_mass, + ag.charges > min_charge, + ag.masses > min_mass, + )) ] return self._group_categories(hydrogens_ag) - def guess_donors(self, select="all", max_charge=-0.5): + def guess_donors(self, select='all', max_charge=-0.5): """Guesses which atoms could be considered donors in the analysis. Only - use if the universe topology does not contain bonding information, + use if the universe topology does not contain bonding information, otherwise donor-hydrogen pairs may be incorrectly assigned. Parameters ---------- select: str (optional) - :ref:`Selection string ` for atom group - from which donors will be identified. (e.g., ``(resname X and name + :ref:`Selection string ` for atom group + from which donors will be identified. (e.g., ``(resname X and name O1)`` or ``type 2``) max_charge: float (optional) The charge of a donor atom must be less than this value. @@ -505,27 +490,27 @@ def guess_donors(self, select="all", max_charge=-0.5): Returns ------- potential_donors: str - String containing the :attr:`resname` and :attr:`name` of all atoms + String containing the :attr:`resname` and :attr:`name` of all atoms that are potentially capable of forming hydrogen bonds. Notes ----- - Donor selections may be achieved with either a resname, atom + Donor selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. - This function makes use of and atomic charges to identify which atoms - could be considered donor atoms in the hydrogen bond analysis. If an - atom has an atomic charge less than :attr:`max_charge`, and it is - within :attr:`d_h_cutoff` of a hydrogen atom, then it is considered + This function makes use of and atomic charges to identify which atoms + could be considered donor atoms in the hydrogen bond analysis. If an + atom has an atomic charge less than :attr:`max_charge`, and it is + within :attr:`d_h_cutoff` of a hydrogen atom, then it is considered capable of participating in hydrogen bonds. - If :attr:`donors_sel` is `None`, and the universe topology does not - have bonding information, this function is called to guess the + If :attr:`donors_sel` is `None`, and the universe topology does not + have bonding information, this function is called to guess the selection. - Alternatively, this function may be used to quickly generate a - :class:`str` of potential donor atoms involved in hydrogen bonding. - This :class:`str` may then be modified before being used to set the + Alternatively, this function may be used to quickly generate a + :class:`str` of potential donor atoms involved in hydrogen bonding. + This :class:`str` may then be modified before being used to set the attribute :attr:`donors_sel`. @@ -535,7 +520,7 @@ def guess_donors(self, select="all", max_charge=-0.5): """ # We need to know `hydrogens_sel` before we can find donors - # Use a new variable `hydrogens_sel` so that we do not set + # Use a new variable `hydrogens_sel` so that we do not set # `self.hydrogens_sel` if it is currently `None` if self.hydrogens_sel is None: hydrogens_sel = self.guess_hydrogens() @@ -547,10 +532,8 @@ def guess_donors(self, select="all", max_charge=-0.5): # times faster to access. This is because u.bonds also calculates # properties of each bond (e.g bond length). See: # https://github.com/MDAnalysis/mdanalysis/issues/2396#issuecomment-596251787 - if ( - hasattr(self.u._topology, "bonds") - and len(self.u._topology.bonds.values) != 0 - ): + if (hasattr(self.u._topology, 'bonds') + and len(self.u._topology.bonds.values) != 0): donors_ag = find_hydrogen_donors(hydrogens_ag) donors_ag = donors_ag.intersection(self.u.select_atoms(select)) else: @@ -558,7 +541,7 @@ def guess_donors(self, select="all", max_charge=-0.5): "({donors_sel}) and around {d_h_cutoff} {hydrogens_sel}".format( donors_sel=select, d_h_cutoff=self.d_h_cutoff, - hydrogens_sel=hydrogens_sel, + hydrogens_sel=hydrogens_sel ) ) @@ -566,17 +549,17 @@ def guess_donors(self, select="all", max_charge=-0.5): return self._group_categories(donors_ag) - def guess_acceptors(self, select="all", max_charge=-0.5): + def guess_acceptors(self, select='all', max_charge=-0.5): """Guesses which atoms could be considered acceptors in the analysis. - Acceptor selections may be achieved with either a resname, atom + Acceptor selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. Parameters ---------- select: str (optional) :ref:`Selection string ` for atom group - from which acceptors will be identified. (e.g., ``(resname X and + from which acceptors will be identified. (e.g., ``(resname X and name O1)`` or ``type 2``) max_charge: float (optional) The charge of an acceptor atom must be less than this value. @@ -584,25 +567,25 @@ def guess_acceptors(self, select="all", max_charge=-0.5): Returns ------- potential_acceptors: str - String containing the :attr:`resname` and :attr:`name` of all atoms + String containing the :attr:`resname` and :attr:`name` of all atoms that potentially capable of forming hydrogen bonds. Notes ----- - Acceptor selections may be achieved with either a resname, atom + Acceptor selections may be achieved with either a resname, atom name combination, or when those are absent, atom types. - This function makes use of and atomic charges to identify which atoms - could be considered acceptor atoms in the hydrogen bond analysis. If - an atom has an atomic charge less than :attr:`max_charge` then it is + This function makes use of and atomic charges to identify which atoms + could be considered acceptor atoms in the hydrogen bond analysis. If + an atom has an atomic charge less than :attr:`max_charge` then it is considered capable of participating in hydrogen bonds. - If :attr:`acceptors_sel` is `None`, this function is called to guess + If :attr:`acceptors_sel` is `None`, this function is called to guess the selection. - Alternatively, this function may be used to quickly generate a - :class:`str` of potential acceptor atoms involved in hydrogen bonding. - This :class:`str` may then be modified before being used to set the + Alternatively, this function may be used to quickly generate a + :class:`str` of potential acceptor atoms involved in hydrogen bonding. + This :class:`str` may then be modified before being used to set the attribute :attr:`acceptors_sel`. @@ -618,14 +601,14 @@ def guess_acceptors(self, select="all", max_charge=-0.5): @staticmethod def _group_categories(group): - """Find categories according to universe constraints - + """ Find categories according to universe constraints + Parameters ---------- group : AtomGroup - AtomGroups corresponding to either hydrogen bond acceptors, + AtomGroups corresponding to either hydrogen bond acceptors, donors, or hydrogen atoms that meet their respective charge - and mass constraints. + and mass constraints. Returns ------- @@ -638,14 +621,16 @@ def _group_categories(group): """ if hasattr(group, "resnames") and hasattr(group, "names"): + group_list = np.unique([ + '(resname {} and name {})'.format(r, + p) for r, p in zip(group.resnames, group.names) + ]) + else: group_list = np.unique( [ - "(resname {} and name {})".format(r, p) - for r, p in zip(group.resnames, group.names) + 'type {}'.format(tp) for tp in group.types ] ) - else: - group_list = np.unique(["type {}".format(tp) for tp in group.types]) return " or ".join(group_list) @@ -655,7 +640,7 @@ def _get_dh_pairs(self): Returns ------- donors, hydrogens: AtomGroup, AtomGroup - AtomGroups corresponding to all donors and all hydrogens. + AtomGroups corresponding to all donors and all hydrogens. AtomGroups are ordered such that, if zipped, will produce a list of donor-hydrogen pairs. """ @@ -666,23 +651,15 @@ def _get_dh_pairs(self): # We're using u._topology.bonds rather than u.bonds as it is a million times faster to access. # This is because u.bonds also calculates properties of each bond (e.g bond length). # See https://github.com/MDAnalysis/mdanalysis/issues/2396#issuecomment-596251787 - if not ( - hasattr(self.u._topology, "bonds") - and len(self.u._topology.bonds.values) != 0 - ): - raise NoDataError( - "Cannot assign donor-hydrogen pairs via topology as no bond information is present. " - "Please either: load a topology file with bond information; use the guess_bonds() " - "topology guesser; or set HydrogenBondAnalysis.donors_sel so that a distance cutoff " - "can be used." - ) + if not (hasattr(self.u._topology, 'bonds') and len(self.u._topology.bonds.values) != 0): + raise NoDataError('Cannot assign donor-hydrogen pairs via topology as no bond information is present. ' + 'Please either: load a topology file with bond information; use the guess_bonds() ' + 'topology guesser; or set HydrogenBondAnalysis.donors_sel so that a distance cutoff ' + 'can be used.') hydrogens = self.u.select_atoms(self.hydrogens_sel) - donors = ( - sum(h.bonded_atoms[0] for h in hydrogens) - if hydrogens + donors = sum(h.bonded_atoms[0] for h in hydrogens) if hydrogens \ else AtomGroup([], self.u) - ) # Otherwise, use d_h_cutoff as a cutoff distance else: @@ -694,7 +671,7 @@ def _get_dh_pairs(self): hydrogens.positions, max_cutoff=self.d_h_cutoff, box=self.u.dimensions, - return_distances=False, + return_distances=False ).T donors = donors[donors_indices] @@ -705,20 +682,20 @@ def _get_dh_pairs(self): def _filter_atoms(self, donors, acceptors): """Create a mask to filter donor, hydrogen and acceptor atoms. - This can be used to consider only hydrogen bonds between two or more - specified groups. + This can be used to consider only hydrogen bonds between two or more + specified groups. - Groups are specified with the `between` keyword when creating the - HydrogenBondAnalysis object. + Groups are specified with the `between` keyword when creating the + HydrogenBondAnalysis object. - Returns - ------- - mask: np.ndarray + Returns + ------- + mask: np.ndarray - .. versionchanged:: 2.5.0 - Change return value to a mask instead of separate AtomGroups. - `` + .. versionchanged:: 2.5.0 + Change return value to a mask instead of separate AtomGroups. +`` """ mask = np.full(donors.n_atoms, fill_value=False) @@ -726,25 +703,27 @@ def _filter_atoms(self, donors, acceptors): # Find donors in G1 and acceptors in G2 mask[ - np.logical_and( - np.isin(donors.indices, group1.indices), - np.isin(acceptors.indices, group2.indices), - ) + np.logical_and( + np.isin(donors.indices, group1.indices), + np.isin(acceptors.indices, group2.indices) + ) ] = True # Find acceptors in G1 and donors in G2 mask[ np.logical_and( np.isin(acceptors.indices, group1.indices), - np.isin(donors.indices, group2.indices), + np.isin(donors.indices, group2.indices) ) ] = True return mask + def _prepare(self): self.results.hbonds = [[], [], [], [], [], []] + def _single_frame(self): box = self._ts.dimensions @@ -791,7 +770,7 @@ def _single_frame(self): tmp_donors.positions, tmp_hydrogens.positions, tmp_acceptors.positions, - box=box, + box=box ) ) hbond_indices = np.where(d_h_a_angles > self.d_h_a_angle)[0] @@ -811,7 +790,8 @@ def _single_frame(self): hbond_angles = d_h_a_angles[hbond_indices] # Store data on hydrogen bonds found at this frame - self.results.hbonds[0].extend(np.full_like(hbond_donors, self._ts.frame)) + self.results.hbonds[0].extend(np.full_like(hbond_donors, + self._ts.frame)) self.results.hbonds[1].extend(hbond_donors.indices) self.results.hbonds[2].extend(hbond_hydrogens.indices) self.results.hbonds[3].extend(hbond_acceptors.indices) @@ -823,15 +803,13 @@ def _conclude(self): self.results.hbonds = np.asarray(self.results.hbonds).T def _get_aggregator(self): - return ResultsGroup(lookup={"hbonds": ResultsGroup.ndarray_hstack}) + return ResultsGroup(lookup={'hbonds': ResultsGroup.ndarray_hstack}) @property def hbonds(self): - wmsg = ( - "The `hbonds` attribute was deprecated in MDAnalysis 2.0.0 " - "and will be removed in MDAnalysis 3.0.0. Please use " - "`results.hbonds` instead." - ) + wmsg = ("The `hbonds` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.hbonds` instead.") warnings.warn(wmsg, DeprecationWarning) return self.results.hbonds @@ -886,7 +864,8 @@ def lifetime(self, tau_max=20, window_step=1, intermittency=0): "before the hydrogen bonds are found" ) logger.error( - "Autocorrelation: Please use the .run() before calling this" "function" + "Autocorrelation: Please use the .run() before calling this" + "function" ) raise NoDataError(".hbonds attribute is None: use .run() first") @@ -911,10 +890,13 @@ def lifetime(self, tau_max=20, window_step=1, intermittency=0): found_hydrogen_bonds[frame_index].add(frozenset(hbond[2:4])) intermittent_hbonds = correct_intermittency( - found_hydrogen_bonds, intermittency=intermittency + found_hydrogen_bonds, + intermittency=intermittency ) tau_timeseries, timeseries, timeseries_data = autocorrelation( - intermittent_hbonds, tau_max, window_step=window_step + intermittent_hbonds, + tau_max, + window_step=window_step ) return np.vstack([tau_timeseries, timeseries]) @@ -930,9 +912,8 @@ def count_by_time(self): the number of hydrogen bonds over time. """ - indices, tmp_counts = np.unique( - self.results.hbonds[:, 0], axis=0, return_counts=True - ) + indices, tmp_counts = np.unique(self.results.hbonds[:, 0], axis=0, + return_counts=True) indices -= self.start indices /= self.step @@ -948,13 +929,13 @@ def count_by_type(self): Returns ------- counts : numpy.ndarray - Each row of the array contains the donor resname, donor atom type, - acceptor resname, acceptor atom type and the total number of times + Each row of the array contains the donor resname, donor atom type, + acceptor resname, acceptor atom type and the total number of times the hydrogen bond was found. Note ---- - Unique hydrogen bonds are determined through a consideration of the + Unique hydrogen bonds are determined through a consideration of the resname and atom type of the donor and acceptor atoms in a hydrogen bond. """ @@ -969,12 +950,12 @@ def count_by_type(self): a_res = len(a.types) * ["None"] tmp_hbonds = np.array([d_res, d.types, a_res, a.types], dtype=str).T - hbond_type, type_counts = np.unique(tmp_hbonds, axis=0, return_counts=True) + hbond_type, type_counts = np.unique( + tmp_hbonds, axis=0, return_counts=True) hbond_type_list = [] for hb_type, hb_count in zip(hbond_type, type_counts): - hbond_type_list.append( - [":".join(hb_type[:2]), ":".join(hb_type[2:4]), hb_count] - ) + hbond_type_list.append([":".join(hb_type[:2]), + ":".join(hb_type[2:4]), hb_count]) return np.array(hbond_type_list) @@ -998,10 +979,12 @@ def count_by_ids(self): a = self.u.atoms[self.results.hbonds[:, 3].astype(np.intp)] tmp_hbonds = np.array([d.ids, h.ids, a.ids]).T - hbond_ids, ids_counts = np.unique(tmp_hbonds, axis=0, return_counts=True) + hbond_ids, ids_counts = np.unique(tmp_hbonds, axis=0, + return_counts=True) # Find unique hbonds and sort rows so that most frequent observed bonds are at the top of the array - unique_hbonds = np.concatenate((hbond_ids, ids_counts[:, None]), axis=1) + unique_hbonds = np.concatenate((hbond_ids, ids_counts[:, None]), + axis=1) unique_hbonds = unique_hbonds[unique_hbonds[:, 3].argsort()[::-1]] return unique_hbonds @@ -1009,7 +992,7 @@ def count_by_ids(self): @property def donors_sel(self): """Selection string for the hydrogen bond donor atoms. - + .. versionadded:: 2.10.0 """ return self._donors_sel @@ -1022,7 +1005,7 @@ def donors_sel(self, value): @property def hydrogens_sel(self): """Selection string for the hydrogen bond hydrogen atoms. - + .. versionadded:: 2.10.0 """ return self._hydrogens_sel @@ -1037,7 +1020,7 @@ def hydrogens_sel(self, value): @property def acceptors_sel(self): """Selection string for the hydrogen bond acceptor atoms. - + .. versionadded:: 2.10.0 """ return self._acceptors_sel @@ -1047,6 +1030,5 @@ def acceptors_sel(self, value): self._acceptors_sel = value if self._acceptors_sel is None: self._acceptors_sel = self.guess_acceptors() - self._acceptors = self.u.select_atoms( - self._acceptors_sel, updating=self.update_selections - ) + self._acceptors = self.u.select_atoms(self._acceptors_sel, + updating=self.update_selections) \ No newline at end of file diff --git a/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py b/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py index 19198e4f69..749fe3533c 100644 --- a/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py +++ b/package/MDAnalysis/analysis/hydrogenbonds/hbond_autocorrel.py @@ -328,16 +328,20 @@ def __init__( if exclusions is not None: if len(exclusions[0]) != len(exclusions[1]): - raise ValueError("'exclusion' must be two arrays of identical length") - self.exclusions = np.column_stack((exclusions[0], exclusions[1])).astype( - np.intp - ) + raise ValueError( + "'exclusion' must be two arrays of identical length" + ) + self.exclusions = np.column_stack( + (exclusions[0], exclusions[1]) + ).astype(np.intp) else: self.exclusions = None self.bond_type = bond_type if self.bond_type not in ["continuous", "intermittent"]: - raise ValueError("bond_type must be either 'continuous' or 'intermittent'") + raise ValueError( + "bond_type must be either 'continuous' or 'intermittent'" + ) self.a_crit = np.deg2rad(angle_crit) self.d_crit = dist_crit @@ -367,7 +371,9 @@ def _slice_traj(self, sample_time): if req_frames > n_frames: warnings.warn( "Number of required frames ({}) greater than the" - " number of frames in trajectory ({})".format(req_frames, n_frames), + " number of frames in trajectory ({})".format( + req_frames, n_frames + ), RuntimeWarning, ) @@ -471,7 +477,9 @@ def _single_run(self, start, stop): aidx = aidx[idx2] nbonds = len(hidx) # number of hbonds at t=0 - results = np.zeros_like(np.arange(start, stop, self._skip), dtype=np.float32) + results = np.zeros_like( + np.arange(start, stop, self._skip), dtype=np.float32 + ) if self.time_cut: # counter for time criteria @@ -480,7 +488,9 @@ def _single_run(self, start, stop): for i, ts in enumerate(self.u.trajectory[start : stop : self._skip]): box = self.u.dimensions if self.pbc else None - d = calc_bonds(self.h.positions[hidx], self.a.positions[aidx], box=box) + d = calc_bonds( + self.h.positions[hidx], self.a.positions[aidx], box=box + ) a = calc_angles( self.d.positions[hidx], self.h.positions[hidx], @@ -605,7 +615,9 @@ def triple(x, A1, A2, tau1, tau2, tau3): """Sum of three exponential functions""" A3 = 1 - (A1 + A2) return ( - A1 * np.exp(-x / tau1) + A2 * np.exp(-x / tau2) + A3 * np.exp(-x / tau3) + A1 * np.exp(-x / tau1) + + A2 * np.exp(-x / tau2) + + A3 * np.exp(-x / tau3) ) if self.bond_type == "continuous": @@ -646,7 +658,9 @@ def triple(x, A1, A2, tau1, tau2, tau3): self.solution["ier"] = ier if ier in [1, 2, 3, 4]: # solution found if ier is one of these values - self.solution["estimate"] = self._my_solve(self.solution["time"], *p) + self.solution["estimate"] = self._my_solve( + self.solution["time"], *p + ) else: warnings.warn("Solution to results not found", RuntimeWarning) diff --git a/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py b/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py index 776e020b83..027c0b7125 100644 --- a/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py +++ b/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py @@ -789,7 +789,9 @@ class WaterBridgeAnalysis(AnalysisBase): "OH", } ), - "GLYCAM06": tuple({"N", "NT", "O", "O2", "OH", "OS", "OW", "OY", "SM"}), + "GLYCAM06": tuple( + {"N", "NT", "O", "O2", "OH", "OS", "OW", "OY", "SM"} + ), "other": tuple(set([])), } @@ -957,7 +959,9 @@ def __init__( """ - super(WaterBridgeAnalysis, self).__init__(universe.trajectory, **kwargs) + super(WaterBridgeAnalysis, self).__init__( + universe.trajectory, **kwargs + ) self.water_selection = water_selection self.update_water_selection = update_water_selection # per-frame debugging output? @@ -997,7 +1001,9 @@ def __init__( acceptors = () self.forcefield = forcefield self.donors = tuple(set(self.DEFAULT_DONORS[forcefield]).union(donors)) - self.acceptors = tuple(set(self.DEFAULT_ACCEPTORS[forcefield]).union(acceptors)) + self.acceptors = tuple( + set(self.DEFAULT_ACCEPTORS[forcefield]).union(acceptors) + ) if self.selection1_type not in ("both", "donor", "acceptor"): raise ValueError( @@ -1086,11 +1092,15 @@ def _update_selection(self): "Size of selection 1 before filtering:" " {} atoms".format(len(self._s1)) ) - ns_selection_1 = AtomNeighborSearch(self.u.atoms[self._s1], box=self.box) + ns_selection_1 = AtomNeighborSearch( + self.u.atoms[self._s1], box=self.box + ) self._s1 = ns_selection_1.search( self.u.atoms[self._s2], self.selection_distance ).ix - self.logger_debug("Size of selection 1: {0} atoms".format(len(self._s1))) + self.logger_debug( + "Size of selection 1: {0} atoms".format(len(self._s1)) + ) if len(self._s1) == 0: logger.warning( @@ -1105,11 +1115,15 @@ def _update_selection(self): "Size of selection 2 before filtering:" " {} atoms".format(len(self._s2)) ) - ns_selection_2 = AtomNeighborSearch(self.u.atoms[self._s2], box=self.box) + ns_selection_2 = AtomNeighborSearch( + self.u.atoms[self._s2], box=self.box + ) self._s2 = ns_selection_2.search( self.u.atoms[self._s1], self.selection_distance ).ix - self.logger_debug("Size of selection 2: {0} atoms".format(len(self._s2))) + self.logger_debug( + "Size of selection 2: {0} atoms".format(len(self._s2)) + ) if len(self._s2) == 0: logger.warning( @@ -1126,10 +1140,16 @@ def _update_selection(self): .ix ) for atom_ix in self._s1_donors: - self._update_donor_h(atom_ix, self._s1_h_donors, self._s1_donors_h) - self.logger_debug("Selection 1 donors: {0}".format(len(self._s1_donors))) + self._update_donor_h( + atom_ix, self._s1_h_donors, self._s1_donors_h + ) self.logger_debug( - "Selection 1 donor hydrogens: {0}".format(len(self._s1_h_donors)) + "Selection 1 donors: {0}".format(len(self._s1_donors)) + ) + self.logger_debug( + "Selection 1 donor hydrogens: {0}".format( + len(self._s1_h_donors) + ) ) if self.selection1_type in ("acceptor", "both"): self._s1_acceptors = ( @@ -1159,10 +1179,16 @@ def _update_selection(self): .ix ) for atom_ix in self._s2_donors: - self._update_donor_h(atom_ix, self._s2_h_donors, self._s2_donors_h) - self.logger_debug("Selection 2 donors: {0:d}".format(len(self._s2_donors))) + self._update_donor_h( + atom_ix, self._s2_h_donors, self._s2_donors_h + ) self.logger_debug( - "Selection 2 donor hydrogens: {0:d}".format(len(self._s2_h_donors)) + "Selection 2 donors: {0:d}".format(len(self._s2_donors)) + ) + self.logger_debug( + "Selection 2 donor hydrogens: {0:d}".format( + len(self._s2_h_donors) + ) ) def _update_water_selection(self): @@ -1187,7 +1213,9 @@ def _update_water_selection(self): .ix ) - self.logger_debug("Size of water selection: {0} atoms".format(len(self._water))) + self.logger_debug( + "Size of water selection: {0} atoms".format(len(self._water)) + ) if len(self._water) == 0: logger.warning( @@ -1205,7 +1233,9 @@ def _update_water_selection(self): self._update_donor_h( atom_ix, self._water_h_donors, self._water_donors_h ) - self.logger_debug("Water donors: {0}".format(len(self._water_donors))) + self.logger_debug( + "Water donors: {0}".format(len(self._water_donors)) + ) self.logger_debug( "Water donor hydrogens: {0}".format(len(self._water_h_donors)) ) @@ -1214,7 +1244,9 @@ def _update_water_selection(self): .select_atoms("name {0}".format(" ".join(self.acceptors))) .ix ) - self.logger_debug("Water acceptors: {0}".format(len(self._water_acceptors))) + self.logger_debug( + "Water acceptors: {0}".format(len(self._water_acceptors)) + ) def _get_bonded_hydrogens(self, atom): """Find hydrogens bonded within cutoff to `atom`. @@ -1273,14 +1305,18 @@ def _prepare(self): if len(self._s1) and len(self._s2): self._update_water_selection() else: - logger.info("WaterBridgeAnalysis: " "no atoms found in the selection.") + logger.info( + "WaterBridgeAnalysis: " "no atoms found in the selection." + ) logger.info("WaterBridgeAnalysis: initial checks passed.") logger.info("WaterBridgeAnalysis: starting") logger.debug("WaterBridgeAnalysis: donors %r", self.donors) logger.debug("WaterBridgeAnalysis: acceptors %r", self.acceptors) - logger.debug("WaterBridgeAnalysis: water bridge %r", self.water_selection) + logger.debug( + "WaterBridgeAnalysis: water bridge %r", self.water_selection + ) if self.debug: logger.debug("Toggling debug to %r", self.debug) @@ -1394,7 +1430,9 @@ def _single_frame(self): angle, ) = line water_pool[(a_resname, a_resid)] = None - selection_1.append((h_index, d_index, a_index, None, dist, angle)) + selection_1.append( + (h_index, d_index, a_index, None, dist, angle) + ) selection_2.append((a_resname, a_resid)) if self.order > 0: self.logger_debug("Selection 1 Donors <-> Water Acceptors") @@ -1411,7 +1449,9 @@ def _single_frame(self): dist, angle, ) = line - selection_1.append((h_index, d_index, a_index, None, dist, angle)) + selection_1.append( + (h_index, d_index, a_index, None, dist, angle) + ) self.logger_debug("Water Donors <-> Selection 2 Acceptors") results = self._donor2acceptor( @@ -1450,7 +1490,9 @@ def _single_frame(self): angle, ) = line water_pool[(h_resname, h_resid)] = None - selection_1.append((a_index, None, h_index, d_index, dist, angle)) + selection_1.append( + (a_index, None, h_index, d_index, dist, angle) + ) selection_2.append((h_resname, h_resid)) if self.order > 0: @@ -1489,7 +1531,9 @@ def _single_frame(self): dist, angle, ) = line - selection_1.append((a_index, None, h_index, d_index, dist, angle)) + selection_1.append( + (a_index, None, h_index, d_index, dist, angle) + ) if self.order > 1: self.logger_debug("Water donor <-> Water Acceptors") @@ -1566,9 +1610,9 @@ def traverse_water_network(graph, node, end, route, maxdepth, result): for new_node in graph[node]: new_route = route[:] new_route.append(new_node) - new_node = self._expand_timeseries(new_node, "sele1_sele2")[3][ - :2 - ] + new_node = self._expand_timeseries( + new_node, "sele1_sele2" + )[3][:2] traverse_water_network( graph, new_node, end, new_route, maxdepth, result ) @@ -1692,7 +1736,8 @@ def _expand_timeseries(self, entry, output_format=None): atom1, atom2 = atom1, atom2 else: raise KeyError( - "Only 'sele1_sele2' or 'donor_acceptor' are allowed as output " "format" + "Only 'sele1_sele2' or 'donor_acceptor' are allowed as output " + "format" ) return ( @@ -1742,7 +1787,10 @@ def analysis(current, output, *args, **kwargs): link_func=self._compact_link, ) timeseries.append( - [self._expand_timeseries(entry, output_format) for entry in new_frame] + [ + self._expand_timeseries(entry, output_format) + for entry in new_frame + ] ) return timeseries @@ -1789,12 +1837,12 @@ def _count_by_type_analysis(self, current, output, *args, **kwargs): :return: """ - s1_index, to_index, s1, to_residue, dist, angle = self._expand_timeseries( - current[0] + s1_index, to_index, s1, to_residue, dist, angle = ( + self._expand_timeseries(current[0]) ) s1_resname, s1_resid, s1_name = s1 - from_index, s2_index, from_residue, s2, dist, angle = self._expand_timeseries( - current[-1] + from_index, s2_index, from_residue, s2, dist, angle = ( + self._expand_timeseries(current[-1]) ) s2_resname, s2_resid, s2_name = s2 key = ( @@ -1860,18 +1908,20 @@ def count_by_type(self, analysis_func=None, **kwargs): for i, key in enumerate(result_dict) ] else: - result = [(key, result_dict[key] / length) for key in result_dict] + result = [ + (key, result_dict[key] / length) for key in result_dict + ] return result else: return None def _count_by_time_analysis(self, current, output, *args, **kwargs): - s1_index, to_index, s1, to_residue, dist, angle = self._expand_timeseries( - current[0] + s1_index, to_index, s1, to_residue, dist, angle = ( + self._expand_timeseries(current[0]) ) s1_resname, s1_resid, s1_name = s1 - from_index, s2_index, from_residue, s2, dist, angle = self._expand_timeseries( - current[-1] + from_index, s2_index, from_residue, s2, dist, angle = ( + self._expand_timeseries(current[-1]) ) s2_resname, s2_resid, s2_name = s2 key = ( @@ -1913,18 +1963,20 @@ def count_by_time(self, analysis_func=None, **kwargs): link_func=self._full_link, **kwargs, ) - result.append((time, sum([result_dict[key] for key in result_dict]))) + result.append( + (time, sum([result_dict[key] for key in result_dict])) + ) return result else: return None def _timesteps_by_type_analysis(self, current, output, *args, **kwargs): - s1_index, to_index, s1, to_residue, dist, angle = self._expand_timeseries( - current[0] + s1_index, to_index, s1, to_residue, dist, angle = ( + self._expand_timeseries(current[0]) ) s1_resname, s1_resid, s1_name = s1 - from_index, s2_index, from_residue, s2, dist, angle = self._expand_timeseries( - current[-1] + from_index, s2_index, from_residue, s2, dist, angle = ( + self._expand_timeseries(current[-1]) ) s2_resname, s2_resid, s2_name = s2 key = ( @@ -2023,7 +2075,10 @@ def generate_table(self, output_format=None): logger.warning(msg) return None - if self.results.timeseries is not None and output_format == self.output_format: + if ( + self.results.timeseries is not None + and output_format == self.output_format + ): timeseries = self.results.timeseries else: # Recompute timeseries with correct output format @@ -2082,7 +2137,9 @@ def generate_table(self, output_format=None): + (distance, angle) ) cursor += 1 - assert cursor == num_records, "Internal Error: Not all wb records stored" + assert ( + cursor == num_records + ), "Internal Error: Not all wb records stored" table = out.view(np.rec.recarray) logger.debug( "WBridge: Stored results as table with %(num_records)d entries.", diff --git a/package/MDAnalysis/analysis/leaflet.py b/package/MDAnalysis/analysis/leaflet.py index 9c735716d9..9ba5de87e7 100644 --- a/package/MDAnalysis/analysis/leaflet.py +++ b/package/MDAnalysis/analysis/leaflet.py @@ -249,7 +249,10 @@ def update(self, cutoff=None): def sizes(self): """Dict of component index with size of component.""" return dict( - ((idx, len(component)) for idx, component in enumerate(self.components)) + ( + (idx, len(component)) + for idx, component in enumerate(self.components) + ) ) def groups(self, component_index=None): diff --git a/package/MDAnalysis/analysis/legacy/x3dna.py b/package/MDAnalysis/analysis/legacy/x3dna.py index ba57edc263..2365c18113 100644 --- a/package/MDAnalysis/analysis/legacy/x3dna.py +++ b/package/MDAnalysis/analysis/legacy/x3dna.py @@ -330,7 +330,9 @@ def save(self, filename="x3dna.pickle"): """ import cPickle - cPickle.dump(self.profiles, open(filename, "wb"), cPickle.HIGHEST_PROTOCOL) + cPickle.dump( + self.profiles, open(filename, "wb"), cPickle.HIGHEST_PROTOCOL + ) def mean_std(self): """Returns the mean and standard deviation of base parameters. @@ -671,7 +673,9 @@ def __init__(self, filename, **kwargs): self.x3dna_param = kwargs.pop("x3dna_param", True) self.exe["xdna_ensemble"] = which(x3dna_exe_name) if self.exe["xdna_ensemble"] is None: - errmsg = "X3DNA binary {x3dna_exe_name!r} not found.".format(**vars()) + errmsg = "X3DNA binary {x3dna_exe_name!r} not found.".format( + **vars() + ) logger.fatal(errmsg) logger.fatal( "%(x3dna_exe_name)r must be on the PATH or provided as keyword argument 'executable'.", @@ -715,7 +719,9 @@ def run(self, **kwargs): f.write(inp) logger.debug("Wrote X3DNA input file %r for inspection", inpname) - logger.info("Starting X3DNA on %(filename)r (trajectory: %(dcd)r)", x3dnaargs) + logger.info( + "Starting X3DNA on %(filename)r (trajectory: %(dcd)r)", x3dnaargs + ) logger.debug("%s", self.exe["xdna_ensemble"]) with open(outname, "w") as output: x3dna = subprocess.call([inp], shell=True) @@ -766,18 +772,20 @@ def collect(self, **kwargs): outdir = kwargs.pop("outdir", os.path.curdir) logger.info("Collecting X3DNA profiles for run with id %s", run) - length = ( - 1 # length of trajectory --- is this really needed?? No... just for info - ) + length = 1 # length of trajectory --- is this really needed?? No... just for info if "*" in self.filename: import glob filenames = glob.glob(self.filename) length = len(filenames) if length == 0: - logger.error("Glob pattern %r did not find any files.", self.filename) + logger.error( + "Glob pattern %r did not find any files.", self.filename + ) raise ValueError( - "Glob pattern {0!r} did not find any files.".format(self.filename) + "Glob pattern {0!r} did not find any files.".format( + self.filename + ) ) logger.info( "Found %d input files based on glob pattern %s", @@ -834,7 +842,9 @@ def collect(self, **kwargs): run, line.strip(), ) - logger.exception("Check input file %r.", x3dna_output) + logger.exception( + "Check input file %r.", x3dna_output + ) raise records.append( [ @@ -884,7 +894,9 @@ def collect(self, **kwargs): run, line.strip(), ) - logger.exception("Check input file %r.", x3dna_output) + logger.exception( + "Check input file %r.", x3dna_output + ) raise records.append( [ @@ -929,7 +941,9 @@ def collect(self, **kwargs): os.makedirs(rundir) frame_x3dna_txt = os.path.join( rundir, - "bp_step_{0!s}_{1:04d}.dat.gz".format(run, x3dna_profile_no), + "bp_step_{0!s}_{1:04d}.dat.gz".format( + run, x3dna_profile_no + ), ) np.savetxt(frame_x3dna_txt, frame_x3dna_output) logger.debug( @@ -939,7 +953,9 @@ def collect(self, **kwargs): ) # if we get here then we haven't found anything interesting if len(self.profiles) == length: - logger.info("Collected X3DNA profiles for %d frames", len(self.profiles)) + logger.info( + "Collected X3DNA profiles for %d frames", len(self.profiles) + ) else: logger.warning( "Missing data: Found %d X3DNA profiles from %d frames.", @@ -1057,10 +1073,8 @@ def run(self, **kwargs): except OSError: pass if len(x3dna_profiles) != 1: - err_msg = ( - "Got {0} profiles ({1}) --- should be 1 (time step {2})".format( - len(x3dna_profiles), x3dna_profiles.keys(), ts - ) + err_msg = "Got {0} profiles ({1}) --- should be 1 (time step {2})".format( + len(x3dna_profiles), x3dna_profiles.keys(), ts ) logger.error(err_msg) warnings.warn(err_msg) diff --git a/package/MDAnalysis/analysis/lineardensity.py b/package/MDAnalysis/analysis/lineardensity.py index 77ea48bf43..369ade9b37 100644 --- a/package/MDAnalysis/analysis/lineardensity.py +++ b/package/MDAnalysis/analysis/lineardensity.py @@ -62,7 +62,9 @@ def _deprecation_warning(self, key): def __getitem__(self, key): if key in self._deprecation_dict.keys(): self._deprecation_warning(key) - return super(Results, self).__getitem__(self._deprecation_dict[key]) + return super(Results, self).__getitem__( + self._deprecation_dict[key] + ) return super(Results, self).__getitem__(key) def __getattr__(self, attr): @@ -212,7 +214,9 @@ def get_supported_backends(cls): ) def __init__(self, select, grouping="atoms", binsize=0.25, **kwargs): - super(LinearDensity, self).__init__(select.universe.trajectory, **kwargs) + super(LinearDensity, self).__init__( + select.universe.trajectory, **kwargs + ) # allows use of run(parallel=True) self._ags = [select] self._universe = select.universe @@ -263,17 +267,23 @@ def __init__(self, select, grouping="atoms", binsize=0.25, **kwargs): self.charges = self._ags[0].total_charge(compound=self.grouping) else: - raise AttributeError(f"{self.grouping} is not a valid value for grouping.") + raise AttributeError( + f"{self.grouping} is not a valid value for grouping." + ) @staticmethod def _custom_aggregator(results): # NB: the *stddev values here are not the standard deviation, # but the variance. The stddev is calculated in _conclude() - mass_density = np.sum([entry["mass_density"] for entry in results], axis=0) + mass_density = np.sum( + [entry["mass_density"] for entry in results], axis=0 + ) mass_density_stddev = np.sum( [entry["mass_density_stddev"] for entry in results], axis=0 ) - charge_density = np.sum([entry["charge_density"] for entry in results], axis=0) + charge_density = np.sum( + [entry["charge_density"] for entry in results], axis=0 + ) charge_density_stddev = np.sum( [entry["charge_density_stddev"] for entry in results], axis=0 ) @@ -306,7 +316,9 @@ def _single_frame(self): self.charges = self._ags[0].total_charge(compound=self.grouping) else: - raise AttributeError(f"{self.grouping} is not a valid value for grouping.") + raise AttributeError( + f"{self.grouping} is not a valid value for grouping." + ) self.group = getattr(self._ags[0], self.grouping) self._ags[0].wrap(compound=self.grouping) @@ -368,17 +380,19 @@ def _conclude(self): # radicand_mass and radicand_charge are therefore calculated first # and negative values set to 0 before the square root # is calculated. - radicand_mass = self.results[dim]["mass_density_stddev"] - np.square( - self.results[dim]["mass_density"] - ) + radicand_mass = self.results[dim][ + "mass_density_stddev" + ] - np.square(self.results[dim]["mass_density"]) radicand_mass[radicand_mass < 0] = 0 self.results[dim]["mass_density_stddev"] = np.sqrt(radicand_mass) - radicand_charge = self.results[dim]["charge_density_stddev"] - np.square( - self.results[dim]["charge_density"] - ) + radicand_charge = self.results[dim][ + "charge_density_stddev" + ] - np.square(self.results[dim]["charge_density"]) radicand_charge[radicand_charge < 0] = 0 - self.results[dim]["charge_density_stddev"] = np.sqrt(radicand_charge) + self.results[dim]["charge_density_stddev"] = np.sqrt( + radicand_charge + ) for dim in ["x", "y", "z"]: # norming factor, units of mol^-1 cm^3 @@ -390,7 +404,8 @@ def _conclude(self): @deprecate( release="2.2.0", remove="3.0.0", - message="It will be replaced by a :meth:`_reduce` " "method in the future", + message="It will be replaced by a :meth:`_reduce` " + "method in the future", ) def _add_other_results(self, other): """For parallel analysis""" diff --git a/package/MDAnalysis/analysis/nucleicacids.py b/package/MDAnalysis/analysis/nucleicacids.py index 9e84119ded..bf68a954cb 100644 --- a/package/MDAnalysis/analysis/nucleicacids.py +++ b/package/MDAnalysis/analysis/nucleicacids.py @@ -182,7 +182,9 @@ def __init__( selection2: List[mda.AtomGroup], **kwargs, ) -> None: - super(NucPairDist, self).__init__(selection1[0].universe.trajectory, **kwargs) + super(NucPairDist, self).__init__( + selection1[0].universe.trajectory, **kwargs + ) if len(selection1) != len(selection2): raise ValueError("Selections must be same length") @@ -266,7 +268,9 @@ def select_strand_atoms( elif pair[0].resname[0] in purines: a1, a2 = a1_name, a2_name else: - raise ValueError(f"AtomGroup in {pair} is not a valid nucleic acid") + raise ValueError( + f"AtomGroup in {pair} is not a valid nucleic acid" + ) ag1 = pair[0].atoms.select_atoms(f"name {a1}") ag2 = pair[1].atoms.select_atoms(f"name {a2}") @@ -289,7 +293,9 @@ def select_strand_atoms( return (sel1, sel2) def _prepare(self) -> None: - self.results.distances: np.ndarray = np.zeros([self.n_frames, self._n_sel]) + self.results.distances: np.ndarray = np.zeros( + [self.n_frames, self._n_sel] + ) def _single_frame(self) -> None: dist: np.ndarray = calc_bonds(self._s1.positions, self._s2.positions) @@ -575,7 +581,9 @@ def __init__( ) ) - super(MinorPairDist, self).__init__(selections[0], selections[1], **kwargs) + super(MinorPairDist, self).__init__( + selections[0], selections[1], **kwargs + ) class MajorPairDist(NucPairDist): @@ -671,4 +679,6 @@ def __init__( ) ) - super(MajorPairDist, self).__init__(selections[0], selections[1], **kwargs) + super(MajorPairDist, self).__init__( + selections[0], selections[1], **kwargs + ) diff --git a/package/MDAnalysis/analysis/pca.py b/package/MDAnalysis/analysis/pca.py index d36ffea00b..fddbf7d009 100644 --- a/package/MDAnalysis/analysis/pca.py +++ b/package/MDAnalysis/analysis/pca.py @@ -614,8 +614,12 @@ def project_single_frame(self, components=None, group=None, anchor=None): non_pca_atoms = np.array([], dtype=int) for res in group.residues: # n_common is the number of pca atoms in a residue - n_common = pca_res_counts[np.where(pca_res_indices == res.resindex)][0] - non_pca_atoms = np.append(non_pca_atoms, res.atoms.n_atoms - n_common) + n_common = pca_res_counts[ + np.where(pca_res_indices == res.resindex) + ][0] + non_pca_atoms = np.append( + non_pca_atoms, res.atoms.n_atoms - n_common + ) # index_extrapolate records the anchor number for each non-PCA atom index_extrapolate = np.repeat( np.arange(anchors.atoms.n_atoms), non_pca_atoms @@ -720,7 +724,9 @@ def rmsip(self, other, n_components=None): b = other.results.p_components except AttributeError: if isinstance(other, type(self)): - raise ValueError("Call run() on the other PCA before using rmsip") + raise ValueError( + "Call run() on the other PCA before using rmsip" + ) else: raise ValueError("other must be another PCA class") @@ -767,7 +773,9 @@ def cumulative_overlap(self, other, i=0, n_components=None): try: a = self.results.p_components except AttributeError: - raise ValueError("Call run() on the PCA before using cumulative_overlap") + raise ValueError( + "Call run() on the PCA before using cumulative_overlap" + ) try: b = other.results.p_components diff --git a/package/MDAnalysis/analysis/polymer.py b/package/MDAnalysis/analysis/polymer.py index 68a2679811..3b78b0b0eb 100644 --- a/package/MDAnalysis/analysis/polymer.py +++ b/package/MDAnalysis/analysis/polymer.py @@ -83,11 +83,14 @@ def sort_backbone(backbone): "".format(",".join(str(a) for a in branches)) ) - caps = [atom for atom in backbone if len(atom.bonded_atoms & backbone) == 1] + caps = [ + atom for atom in backbone if len(atom.bonded_atoms & backbone) == 1 + ] if not caps: # cyclical structure raise ValueError( - "Could not find starting point of backbone, " "is the backbone cyclical?" + "Could not find starting point of backbone, " + "is the backbone cyclical?" ) # arbitrarily choose one of the capping atoms to be the startpoint diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index 5063d522de..c3459ac65f 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -264,7 +264,8 @@ def __init__( if self.norm not in ["rdf", "density", "none"]: raise ValueError( - f"'{self.norm}' is an invalid norm. " "Use 'rdf', 'density' or 'none'." + f"'{self.norm}' is an invalid norm. " + "Use 'rdf', 'density' or 'none'." ) self.backend = backend @@ -588,7 +589,9 @@ def __init__( backend="serial", **kwargs, ): - super(InterRDF_s, self).__init__(ags[0][0].universe.trajectory, **kwargs) + super(InterRDF_s, self).__init__( + ags[0][0].universe.trajectory, **kwargs + ) warnings.warn( "The `u` attribute is superflous and will be removed " @@ -602,7 +605,8 @@ def __init__( if self.norm not in ["rdf", "density", "none"]: raise ValueError( - f"'{self.norm}' is an invalid norm. " "Use 'rdf', 'density' or 'none'." + f"'{self.norm}' is an invalid norm. " + "Use 'rdf', 'density' or 'none'." ) if density: diff --git a/package/MDAnalysis/analysis/results.py b/package/MDAnalysis/analysis/results.py index 37db403d9a..7708f3dd88 100644 --- a/package/MDAnalysis/analysis/results.py +++ b/package/MDAnalysis/analysis/results.py @@ -101,7 +101,9 @@ class in `scikit-learn`_. def _validate_key(self, key): if key in dir(self): - raise AttributeError(f"'{key}' is a protected dictionary attribute") + raise AttributeError( + f"'{key}' is a protected dictionary attribute" + ) elif isinstance(key, str) and not key.isidentifier(): raise ValueError(f"'{key}' is not a valid attribute") @@ -126,13 +128,17 @@ def __getattr__(self, attr): try: return self[attr] except KeyError as err: - raise AttributeError(f"'Results' object has no attribute '{attr}'") from err + raise AttributeError( + f"'Results' object has no attribute '{attr}'" + ) from err def __delattr__(self, attr): try: del self[attr] except KeyError as err: - raise AttributeError(f"'Results' object has no attribute '{attr}'") from err + raise AttributeError( + f"'Results' object has no attribute '{attr}'" + ) from err def __getstate__(self): return self.data diff --git a/package/MDAnalysis/analysis/rms.py b/package/MDAnalysis/analysis/rms.py index d4576ed781..55a1322a75 100644 --- a/package/MDAnalysis/analysis/rms.py +++ b/package/MDAnalysis/analysis/rms.py @@ -312,7 +312,8 @@ def process_selection(select): select = {"mobile": select[0], "reference": select[1]} except IndexError: raise IndexError( - "select must contain two selection strings " "(reference, mobile)" + "select must contain two selection strings " + "(reference, mobile)" ) from None elif type(select) is dict: # compatability hack to use new nomenclature @@ -551,7 +552,9 @@ def __init__( ) logger.exception(err) raise SelectionError(err) - logger.info("RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms))) + logger.info( + "RMS calculation " "for {0:d} atoms.".format(len(self.ref_atoms)) + ) mass_mismatches = ( np.absolute((self.ref_atoms.masses - self.mobile_atoms.masses)) > self.tol_mass @@ -593,7 +596,9 @@ def __init__( # *groupselections* groups each a dict with reference/mobile self._groupselections_atoms = [ { - "reference": self.reference.universe.select_atoms(*s["reference"]), + "reference": self.reference.universe.select_atoms( + *s["reference"] + ), "mobile": self.atomgroup.universe.select_atoms(*s["mobile"]), } for s in self.groupselections @@ -656,18 +661,23 @@ def __init__( get_weights(atoms["mobile"], weights) except Exception as e: raise type(e)( - str(e) + " happens in selection %s" % selection["mobile"] + str(e) + + " happens in selection %s" % selection["mobile"] ) def _prepare(self): self._n_atoms = self.mobile_atoms.n_atoms if not self.weights_groupselections: - if not iterable(self.weights): # apply 'mass' or 'None' to groupselections + if not iterable( + self.weights + ): # apply 'mass' or 'None' to groupselections self.weights_groupselections = [self.weights] * len( self.groupselections ) else: - self.weights_groupselections = [None] * len(self.groupselections) + self.weights_groupselections = [None] * len( + self.groupselections + ) for igroup, (weights, atoms) in enumerate( zip(self.weights_groupselections, self._groupselections_atoms) @@ -685,9 +695,9 @@ def _prepare(self): self.weights_select = np.asarray( self.weights_select, dtype=np.float64 ) / np.mean(self.weights_select) - self.weights_ref = np.asarray(self.weights_ref, dtype=np.float64) / np.mean( - self.weights_ref - ) + self.weights_ref = np.asarray( + self.weights_ref, dtype=np.float64 + ) / np.mean(self.weights_ref) current_frame = self.reference.universe.trajectory.ts.frame @@ -702,9 +712,9 @@ def _prepare(self): if self._groupselections_atoms: self._groupselections_ref_coords64 = [ ( - self.reference.select_atoms(*s["reference"]).positions.astype( - np.float64 - ) + self.reference.select_atoms( + *s["reference"] + ).positions.astype(np.float64) ) for s in self.groupselections ] @@ -737,7 +747,9 @@ def _get_aggregator(self): return ResultsGroup(lookup={"rmsd": ResultsGroup.ndarray_vstack}) def _single_frame(self): - mobile_com = self.mobile_atoms.center(self.weights_select).astype(np.float64) + mobile_com = self.mobile_atoms.center(self.weights_select).astype( + np.float64 + ) self._mobile_coordinates64[:] = self.mobile_atoms.positions self._mobile_coordinates64 -= mobile_com @@ -753,12 +765,14 @@ def _single_frame(self): # left** so that we can easily use broadcasting and save one # expensive numpy transposition. - self.results.rmsd[self._frame_index, 2] = qcp.CalcRMSDRotationalMatrix( - self._ref_coordinates64, - self._mobile_coordinates64, - self._n_atoms, - self._rot, - self.weights_select, + self.results.rmsd[self._frame_index, 2] = ( + qcp.CalcRMSDRotationalMatrix( + self._ref_coordinates64, + self._mobile_coordinates64, + self._n_atoms, + self._rot, + self.weights_select, + ) ) self._R[:, :] = self._rot.reshape(3, 3) @@ -790,12 +804,14 @@ def _single_frame(self): else: # only calculate RMSD by setting the Rmatrix to None (no need # to carry out the rotation as we already get the optimum RMSD) - self.results.rmsd[self._frame_index, 2] = qcp.CalcRMSDRotationalMatrix( - self._ref_coordinates64, - self._mobile_coordinates64, - self._n_atoms, - None, - self.weights_select, + self.results.rmsd[self._frame_index, 2] = ( + qcp.CalcRMSDRotationalMatrix( + self._ref_coordinates64, + self._mobile_coordinates64, + self._n_atoms, + None, + self.weights_select, + ) ) @property @@ -959,7 +975,9 @@ def _prepare(self): def _single_frame(self): k = self._frame_index - self.sumsquares += (k / (k + 1.0)) * (self.atomgroup.positions - self.mean) ** 2 + self.sumsquares += (k / (k + 1.0)) * ( + self.atomgroup.positions - self.mean + ) ** 2 self.mean = (k * self.mean + self.atomgroup.positions) / (k + 1) def _conclude(self): @@ -968,7 +986,8 @@ def _conclude(self): if not (self.results.rmsf >= 0).all(): raise ValueError( - "Some RMSF values negative; overflow " + "or underflow occurred" + "Some RMSF values negative; overflow " + + "or underflow occurred" ) @property diff --git a/package/MDAnalysis/auxiliary/EDR.py b/package/MDAnalysis/auxiliary/EDR.py index 74d1579d16..8b9149690e 100644 --- a/package/MDAnalysis/auxiliary/EDR.py +++ b/package/MDAnalysis/auxiliary/EDR.py @@ -316,7 +316,9 @@ class EDRReader(base.AuxReader): def __init__(self, filename: str, convert_units: bool = True, **kwargs): if not HAS_PYEDR: - raise ImportError("EDRReader: To read EDR files please install " "pyedr.") + raise ImportError( + "EDRReader: To read EDR files please install " "pyedr." + ) self._auxdata = Path(filename).resolve() self.data_dict = pyedr.edr_to_dict(filename) self.unit_dict = pyedr.get_unit_dictionary(filename) @@ -346,7 +348,8 @@ def _convert_units(self): self.unit_dict[term] = units.MDANALYSIS_BASE_UNITS[unit_type] if unknown_units: warnings.warn( - "Could not find unit type for the following " f"units: {unknown_units}" + "Could not find unit type for the following " + f"units: {unknown_units}" ) def _memory_usage(self): @@ -372,7 +375,8 @@ def _read_next_step(self) -> EDRStep: new_step = self.step + 1 if new_step < self.n_steps: auxstep._data = { - term: self.data_dict[term][self.step + 1] for term in self.terms + term: self.data_dict[term][self.step + 1] + for term in self.terms } auxstep.step = new_step return auxstep diff --git a/package/MDAnalysis/auxiliary/base.py b/package/MDAnalysis/auxiliary/base.py index 12ae24cf61..29fbaf999a 100644 --- a/package/MDAnalysis/auxiliary/base.py +++ b/package/MDAnalysis/auxiliary/base.py @@ -193,7 +193,9 @@ def _time_selector(self, new): select = self._select_time except AttributeError: warnings.warn( - "{} does not support time selection".format(self.__class__.__name__) + "{} does not support time selection".format( + self.__class__.__name__ + ) ) else: # check *new* is valid before setting; _select_time should raise @@ -232,7 +234,9 @@ def _data_selector(self, new): select = self._select_data except AttributeError: warnings.warn( - "{} does not support data selection".format(self.__class__.__name__) + "{} does not support data selection".format( + self.__class__.__name__ + ) ) else: # check *new* is valid before setting; _select_data should raise an @@ -325,7 +329,9 @@ class AuxReader(metaclass=_AuxReaderMeta): "_auxdata", ] - def __init__(self, represent_ts_as="closest", auxname=None, cutoff=None, **kwargs): + def __init__( + self, represent_ts_as="closest", auxname=None, cutoff=None, **kwargs + ): # allow auxname to be optional for when using reader separate from # trajectory. self.auxname = auxname @@ -625,7 +631,9 @@ def step_to_frame(self, step, ts, return_time_diff=False): return None time_frame_0 = ts.time - ts.frame * ts.dt # assumes ts.dt is constant time_step = self.step_to_time(step) - frame_index = int(math.floor((time_step - time_frame_0 + ts.dt / 2.0) / ts.dt)) + frame_index = int( + math.floor((time_step - time_frame_0 + ts.dt / 2.0) / ts.dt) + ) if not return_time_diff: return frame_index else: @@ -650,7 +658,9 @@ def move_to_ts(self, ts): # figure out what step we want to end up at if self.constant_dt: # if dt constant, calculate from dt/offset/etc - step = int(math.floor((ts.time - ts.dt / 2 - self.initial_time) / self.dt)) + step = int( + math.floor((ts.time - ts.dt / 2 - self.initial_time) / self.dt) + ) # if we're out of range of the number of steps, reset back step = max(min(step, self.n_steps - 1), -1) else: @@ -739,7 +749,11 @@ def __getitem__(self, i): stop = ( i.stop if i.stop == self.n_steps - else (self._check_index(i.stop) if i.stop is not None else self.n_steps) + else ( + self._check_index(i.stop) + if i.stop is not None + else self.n_steps + ) ) step = i.step or 1 if not isinstance(step, numbers.Integral) or step < 1: @@ -773,7 +787,9 @@ def _slice_iter(self, i): def _go_to_step(self, i): """Move to and read i-th auxiliary step.""" # Need to define in each auxiliary reader - raise NotImplementedError("BUG: Override _go_to_step() in auxiliary reader!") + raise NotImplementedError( + "BUG: Override _go_to_step() in auxiliary reader!" + ) def _reset_frame_data(self): self.frame_data = {} @@ -837,7 +853,9 @@ def calc_representative(self): value = cutoff_data[min_diff] elif self.represent_ts_as == "average": try: - value = np.mean(np.array([val for val in cutoff_data.values()]), axis=0) + value = np.mean( + np.array([val for val in cutoff_data.values()]), axis=0 + ) except TypeError: # for readers like EDRReader, the above does not work # because each step contains a dictionary of numpy arrays @@ -949,7 +967,8 @@ def get_description(self): AuxReader. """ description = { - attr.strip("_"): getattr(self, attr) for attr in self.required_attrs + attr.strip("_"): getattr(self, attr) + for attr in self.required_attrs } return description diff --git a/package/MDAnalysis/converters/OpenMM.py b/package/MDAnalysis/converters/OpenMM.py index 9d0c6a6531..76a743b773 100644 --- a/package/MDAnalysis/converters/OpenMM.py +++ b/package/MDAnalysis/converters/OpenMM.py @@ -108,7 +108,9 @@ def _read_first_frame(self): self.ts.triclinic_dimensions = self.convert_pos_from_native( self.ts.triclinic_dimensions, inplace=False ) - self.ts.dimensions[3:] = _sanitize_box_angles(self.ts.dimensions[3:]) + self.ts.dimensions[3:] = _sanitize_box_angles( + self.ts.dimensions[3:] + ) self.convert_velocities_from_native(self.ts._velocities) self.convert_forces_from_native(self.ts._forces) self.convert_time_from_native(self.ts.dt) @@ -135,7 +137,9 @@ def _mda_timestep_from_omm_context(self): ts.data["kinetic_energy"] = ( state.getKineticEnergy().in_units_of(u.kilojoule / u.mole)._value ) - ts.triclinic_dimensions = state.getPeriodicBoxVectors(asNumpy=True)._value + ts.triclinic_dimensions = state.getPeriodicBoxVectors( + asNumpy=True + )._value ts.dimensions[3:] = _sanitize_box_angles(ts.dimensions[3:]) ts.positions = state.getPositions(asNumpy=True)._value ts.velocities = state.getVelocities(asNumpy=True)._value @@ -179,7 +183,9 @@ def _read_first_frame(self): self.ts.triclinic_dimensions = self.convert_pos_from_native( self.ts.triclinic_dimensions, inplace=False ) - self.ts.dimensions[3:] = _sanitize_box_angles(self.ts.dimensions[3:]) + self.ts.dimensions[3:] = _sanitize_box_angles( + self.ts.dimensions[3:] + ) def _mda_timestep_from_omm_app(self): """Construct Timestep object from OpenMM Application object""" diff --git a/package/MDAnalysis/converters/OpenMMParser.py b/package/MDAnalysis/converters/OpenMMParser.py index 4851f7bac9..03fa06a60b 100644 --- a/package/MDAnalysis/converters/OpenMMParser.py +++ b/package/MDAnalysis/converters/OpenMMParser.py @@ -194,7 +194,9 @@ def _mda_topology_from_omm_topology(self, omm_topology): " but it will be removed in 3.0)." ) - attrs.append(Elements(np.array(validated_elements, dtype=object))) + attrs.append( + Elements(np.array(validated_elements, dtype=object)) + ) else: wmsg = ( diff --git a/package/MDAnalysis/converters/ParmEd.py b/package/MDAnalysis/converters/ParmEd.py index 57f6042ffb..e26f880c9f 100644 --- a/package/MDAnalysis/converters/ParmEd.py +++ b/package/MDAnalysis/converters/ParmEd.py @@ -238,7 +238,9 @@ def convert(self, obj): "id", ): try: - akwargs[MDA2PMD.get(attrname, attrname)] = getattr(atom, attrname) + akwargs[MDA2PMD.get(attrname, attrname)] = getattr( + atom, attrname + ) except AttributeError: pass try: @@ -258,7 +260,9 @@ def convert(self, obj): chain_seg["inscode"] = atom.icode except AttributeError: pass - atom_kwargs.append((akwargs, resname, atom.resid, chain_seg, xyz, vel)) + atom_kwargs.append( + (akwargs, resname, atom.resid, chain_seg, xyz, vel) + ) struct = pmd.Structure() @@ -284,7 +288,9 @@ def convert(self, obj): struct.box = None if hasattr(ag_or_ts, "universe"): - atomgroup = {atom: index for index, atom in enumerate(list(ag_or_ts))} + atomgroup = { + atom: index for index, atom in enumerate(list(ag_or_ts)) + } get_atom_indices = functools.partial( get_indices_from_subset, atomgroup=atomgroup, @@ -300,7 +306,9 @@ def convert(self, obj): pass else: for p in params: - atoms = [struct.atoms[i] for i in map(get_atom_indices, p.indices)] + atoms = [ + struct.atoms[i] for i in map(get_atom_indices, p.indices) + ] try: for obj in p.type: bond = pmd.Bond(*atoms, type=obj.type, order=obj.order) @@ -320,12 +328,16 @@ def convert(self, obj): # dihedrals try: - params = ag_or_ts.dihedrals.atomgroup_intersection(ag_or_ts, strict=True) + params = ag_or_ts.dihedrals.atomgroup_intersection( + ag_or_ts, strict=True + ) except AttributeError: pass else: for p in params: - atoms = [struct.atoms[i] for i in map(get_atom_indices, p.indices)] + atoms = [ + struct.atoms[i] for i in map(get_atom_indices, p.indices) + ] try: for obj in p.type: imp = getattr(obj, "improper", False) @@ -341,7 +353,9 @@ def convert(self, obj): btype = getattr(p.type, "type", None) imp = getattr(p.type, "improper", False) ign = getattr(p.type, "ignore_end", False) - dih = pmd.Dihedral(*atoms, type=btype, improper=imp, ignore_end=ign) + dih = pmd.Dihedral( + *atoms, type=btype, improper=imp, ignore_end=ign + ) struct.dihedrals.append(dih) if isinstance(dih.type, pmd.DihedralType): struct.dihedral_types.append(dih.type) @@ -378,7 +392,10 @@ def convert(self, obj): pass else: for v in values: - atoms = [struct.atoms[i] for i in map(get_atom_indices, v.indices)] + atoms = [ + struct.atoms[i] + for i in map(get_atom_indices, v.indices) + ] try: for parmed_obj in v.type: diff --git a/package/MDAnalysis/converters/ParmEdParser.py b/package/MDAnalysis/converters/ParmEdParser.py index 0fdbae4c74..331f14e279 100644 --- a/package/MDAnalysis/converters/ParmEdParser.py +++ b/package/MDAnalysis/converters/ParmEdParser.py @@ -311,7 +311,9 @@ def parse(self, **kwargs): bond_orders = list(map(squash_identical, bond_orders)) attrs.append( - Bonds(bond_values, types=bond_types, guessed=False, order=bond_orders) + Bonds( + bond_values, types=bond_types, guessed=False, order=bond_orders + ) ) for pmdlist, na, values, types in ( diff --git a/package/MDAnalysis/converters/RDKitInferring.py b/package/MDAnalysis/converters/RDKitInferring.py index 6c42464b56..843986371a 100644 --- a/package/MDAnalysis/converters/RDKitInferring.py +++ b/package/MDAnalysis/converters/RDKitInferring.py @@ -92,7 +92,9 @@ ) # available since 2022.09.1 -def reorder_atoms(mol: "Chem.Mol", field: str = "_MDAnalysis_index") -> "Chem.Mol": +def reorder_atoms( + mol: "Chem.Mol", field: str = "_MDAnalysis_index" +) -> "Chem.Mol": """Reorder atoms based on the given field. Defaults to sorting in the same order as the input AtomGroup. @@ -392,7 +394,9 @@ def _standardize_patterns( self._rebuild_conjugated_bonds(mol, max_iter) # list of sanitized reactions - reactions = [ReactionFromSmarts(rxn) for rxn in self.STANDARDIZATION_REACTIONS] + reactions = [ + ReactionFromSmarts(rxn) for rxn in self.STANDARDIZATION_REACTIONS + ] # fragment mol (reactions must have single reactant and product) fragments = list( @@ -481,13 +485,17 @@ def _rebuild_conjugated_bonds( # there's usually an even number of matches for this pattern = Chem.MolFromSmarts("[*-{1-2}]-,=[*+0]=,#[*+0]") # pattern used to finish fixing a series of conjugated bonds - base_end_pattern = Chem.MolFromSmarts("[*-{1-2}]-,=[*+0]=,#[*+0]-,=[*-{1-2}]") + base_end_pattern = Chem.MolFromSmarts( + "[*-{1-2}]-,=[*+0]=,#[*+0]-,=[*-{1-2}]" + ) # used when there's an odd number of matches for `pattern` odd_end_pattern = Chem.MolFromSmarts( "[*-]-[*+0]=[*+0]-[*-,$([#7;X3;v3]),$([#6+0,#7+1]=O),$([S;D4;v4]-[O-])]" ) # number of unique matches with the pattern - n_matches = len({match[0] for match in mol.GetSubstructMatches(pattern)}) + n_matches = len( + {match[0] for match in mol.GetSubstructMatches(pattern)} + ) # nothing to standardize if n_matches == 0: return @@ -515,12 +523,16 @@ def _rebuild_conjugated_bonds( # [*-]-*=*-[C,N+]=O --> *=*-*=[C,N+]-[O-] # transform the =O to -[O-] if ( - term_atom.GetAtomicNum() == 6 and term_atom.GetFormalCharge() == 0 + term_atom.GetAtomicNum() == 6 + and term_atom.GetFormalCharge() == 0 ) or ( - term_atom.GetAtomicNum() == 7 and term_atom.GetFormalCharge() == 1 + term_atom.GetAtomicNum() == 7 + and term_atom.GetFormalCharge() == 1 ): for neighbor in term_atom.GetNeighbors(): - bond = mol.GetBondBetweenAtoms(anion2, neighbor.GetIdx()) + bond = mol.GetBondBetweenAtoms( + anion2, neighbor.GetIdx() + ) if ( neighbor.GetAtomicNum() == 8 and bond.GetBondTypeAsDouble() == 2 @@ -532,10 +544,13 @@ def _rebuild_conjugated_bonds( # [*-]-*=*-[Sv4]-[O-] --> *=*-*=[Sv6]=O # transform -[O-] to =O elif ( - term_atom.GetAtomicNum() == 16 and term_atom.GetFormalCharge() == 0 + term_atom.GetAtomicNum() == 16 + and term_atom.GetFormalCharge() == 0 ): for neighbor in term_atom.GetNeighbors(): - bond = mol.GetBondBetweenAtoms(anion2, neighbor.GetIdx()) + bond = mol.GetBondBetweenAtoms( + anion2, neighbor.GetIdx() + ) if ( neighbor.GetAtomicNum() == 8 and neighbor.GetFormalCharge() == -1 diff --git a/package/MDAnalysis/converters/RDKitParser.py b/package/MDAnalysis/converters/RDKitParser.py index 22e0851b22..90069ebfb1 100644 --- a/package/MDAnalysis/converters/RDKitParser.py +++ b/package/MDAnalysis/converters/RDKitParser.py @@ -215,7 +215,9 @@ def parse(self, **kwargs): return top # check if multiple charges present - if atom.HasProp("_GasteigerCharge") and (atom.HasProp("_TriposPartialCharge")): + if atom.HasProp("_GasteigerCharge") and ( + atom.HasProp("_TriposPartialCharge") + ): warnings.warn( "Both _GasteigerCharge and _TriposPartialCharge properties " "are present. Using Gasteiger charges by default." @@ -257,7 +259,9 @@ def parse(self, **kwargs): except KeyError: # partial charge (MOL2 only) try: - charges.append(atom.GetDoubleProp("_TriposPartialCharge")) + charges.append( + atom.GetDoubleProp("_TriposPartialCharge") + ) except KeyError: pass diff --git a/package/MDAnalysis/coordinates/CRD.py b/package/MDAnalysis/coordinates/CRD.py index 16a0c07ee2..e762c83767 100644 --- a/package/MDAnalysis/coordinates/CRD.py +++ b/package/MDAnalysis/coordinates/CRD.py @@ -82,7 +82,10 @@ def _read_first_frame(self): np.array(line[20:50].split()[0:3], dtype=float) ) except Exception: - errmsg = f"Check CRD format at line {linenum}: " f"{line.rstrip()}" + errmsg = ( + f"Check CRD format at line {linenum}: " + f"{line.rstrip()}" + ) raise ValueError(errmsg) from None self.n_atoms = len(coords_list) @@ -98,7 +101,8 @@ def _read_first_frame(self): if self.n_atoms != natoms: raise ValueError( "Found %d coordinates in %r but the header claims that there " - "should be %d coordinates." % (self.n_atoms, self.filename, natoms) + "should be %d coordinates." + % (self.n_atoms, self.filename, natoms) ) def Writer(self, filename, **kwargs): @@ -213,7 +217,9 @@ def write(self, selection, frame=None): frame = 0 # should catch cases when we are analyzing a single PDB (?) atoms = selection.atoms # make sure to use atoms (Issue 46) - coor = atoms.positions # can write from selection == Universe (Issue 49) + coor = ( + atoms.positions + ) # can write from selection == Universe (Issue 49) n_atoms = len(atoms) # Detect which format string we're using to output (EXT or not) @@ -265,7 +271,9 @@ def write(self, selection, frame=None): with util.openany(self.filename, "wt") as crd: # Write Title crd.write( - self.fmt["TITLE"].format(frame=frame, where=u.trajectory.filename) + self.fmt["TITLE"].format( + frame=frame, where=u.trajectory.filename + ) ) crd.write("*\n") diff --git a/package/MDAnalysis/coordinates/DCD.py b/package/MDAnalysis/coordinates/DCD.py index 6c43a475bf..88c8d76b3e 100644 --- a/package/MDAnalysis/coordinates/DCD.py +++ b/package/MDAnalysis/coordinates/DCD.py @@ -117,10 +117,9 @@ class DCDReader(base.ReaderBase): .. _DCDplugin: http://www.ks.uiuc.edu/Research/vmd/plugins/doxygen/dcdplugin_8c-source.html#l00947 .. _wiki: https://github.com/MDAnalysis/mdanalysis/wiki/FileFormats#dcd """ - - format = "DCD" - flavor = "CHARMM" - units = {"time": "AKMA", "length": "Angstrom"} + format = 'DCD' + flavor = 'CHARMM' + units = {'time': 'AKMA', 'length': 'Angstrom'} @store_init_arguments def __init__(self, filename, convert_units=True, dt=None, **kwargs): @@ -140,16 +139,18 @@ def __init__(self, filename, convert_units=True, dt=None, **kwargs): .. versionchanged:: 0.17.0 Changed to use libdcd.pyx library and removed the correl function """ - super(DCDReader, self).__init__(filename, convert_units=convert_units, **kwargs) + super(DCDReader, self).__init__( + filename, convert_units=convert_units, **kwargs) self._file = DCDFile(self.filename) - self.n_atoms = self._file.header["natoms"] + self.n_atoms = self._file.header['natoms'] - delta = mdaunits.convert(self._file.header["delta"], self.units["time"], "ps") + delta = mdaunits.convert(self._file.header['delta'], + self.units['time'], 'ps') if dt is None: - dt = delta * self._file.header["nsavc"] - self.skip_timestep = self._file.header["nsavc"] + dt = delta * self._file.header['nsavc'] + self.skip_timestep = self._file.header['nsavc'] - self._ts_kwargs["dt"] = dt + self._ts_kwargs['dt'] = dt self.ts = self._Timestep(self.n_atoms, **self._ts_kwargs) frame = self._file.read() # reset trajectory @@ -161,20 +162,18 @@ def __init__(self, filename, convert_units=True, dt=None, **kwargs): self.ts = self._frame_to_ts(frame, self.ts) # these should only be initialized once self.ts.dt = dt - warnings.warn( - "DCDReader currently makes independent timesteps" - " by copying self.ts while other readers update" - " self.ts inplace. This behavior will be changed in" - " 3.0 to be the same as other readers. Read more at" - " https://github.com/MDAnalysis/mdanalysis/issues/3889" - " to learn if this change in behavior might affect you.", - category=DeprecationWarning, - ) + warnings.warn("DCDReader currently makes independent timesteps" + " by copying self.ts while other readers update" + " self.ts inplace. This behavior will be changed in" + " 3.0 to be the same as other readers. Read more at" + " https://github.com/MDAnalysis/mdanalysis/issues/3889" + " to learn if this change in behavior might affect you.", + category=DeprecationWarning) @staticmethod def parse_n_atoms(filename, **kwargs): with DCDFile(filename) as f: - n_atoms = f.header["natoms"] + n_atoms = f.header['natoms'] return n_atoms def close(self): @@ -191,7 +190,7 @@ def _reopen(self): self.ts.frame = 0 self._frame = -1 self._file.close() - self._file.open("r") + self._file.open('r') def _read_frame(self, i): """read frame i""" @@ -202,9 +201,9 @@ def _read_frame(self, i): def _read_next_timestep(self, ts=None): """copy next frame into timestep""" if self._frame == self.n_frames - 1: - raise IOError("trying to go over trajectory limit") + raise IOError('trying to go over trajectory limit') if ts is None: - # TODO remove copying the ts in 3.0 + #TODO remove copying the ts in 3.0 ts = self.ts.copy() frame = self._file.read() self._frame += 1 @@ -221,23 +220,21 @@ def Writer(self, filename, n_atoms=None, **kwargs): n_atoms=n_atoms, dt=self.ts.dt, convert_units=self.convert_units, - **kwargs - ) + **kwargs) def _frame_to_ts(self, frame, ts): """convert a dcd-frame to a :class:`TimeStep`""" ts.frame = self._frame - ts.time = ( - ts.frame + self._file.header["istart"] / self._file.header["nsavc"] - ) * self.ts.dt - ts.data["step"] = self._file.tell() + ts.time = (ts.frame + self._file.header['istart']/self._file.header['nsavc']) * self.ts.dt + ts.data['step'] = self._file.tell() # The original unitcell is read as ``[A, gamma, B, beta, alpha, C]`` _ts_order = [0, 2, 5, 4, 3, 1] uc = np.take(frame.unitcell, _ts_order) pi_2 = np.pi / 2 - if (-1.0 <= uc[3] <= 1.0) and (-1.0 <= uc[4] <= 1.0) and (-1.0 <= uc[5] <= 1.0): + if (-1.0 <= uc[3] <= 1.0) and (-1.0 <= uc[4] <= 1.0) and ( + -1.0 <= uc[5] <= 1.0): # This file was generated by Charmm, or by NAMD > 2.5, with the # angle cosines of the periodic cell angles written to the DCD # file. This formulation improves rounding behavior for orthogonal @@ -248,7 +245,7 @@ def _frame_to_ts(self, frame, ts): uc[4] = 90.0 - np.arcsin(uc[4]) * 90.0 / pi_2 uc[5] = 90.0 - np.arcsin(uc[5]) * 90.0 / pi_2 # heuristic sanity check: uc = A,B,C,alpha,beta,gamma - elif np.any(uc < 0.0) or np.any(uc[3:] > 180.0): + elif np.any(uc < 0.) or np.any(uc[3:] > 180.): # might be new CHARMM: box matrix vectors H = frame.unitcell.copy() e1, e2, e3 = H[[0, 1, 3]], H[[1, 2, 4]], H[[3, 4, 5]] @@ -270,7 +267,8 @@ def _frame_to_ts(self, frame, ts): @property def dimensions(self): - """unitcell dimensions (*A*, *B*, *C*, *alpha*, *beta*, *gamma*)""" + """unitcell dimensions (*A*, *B*, *C*, *alpha*, *beta*, *gamma*) + """ return self.ts.dimensions @property @@ -278,9 +276,13 @@ def dt(self): """timestep between frames""" return self.ts.dt - def timeseries( - self, asel=None, atomgroup=None, start=None, stop=None, step=None, order="afc" - ): + def timeseries(self, + asel=None, + atomgroup=None, + start=None, + stop=None, + step=None, + order='afc'): """Return a subset of coordinate data for an AtomGroup Parameters @@ -289,7 +291,7 @@ def timeseries( The :class:`~MDAnalysis.core.groups.AtomGroup` to read the coordinates from. Defaults to None, in which case the full set of coordinate data is returned. - + .. deprecated:: 2.7.0 asel argument will be renamed to atomgroup in 3.0.0 @@ -324,8 +326,7 @@ def timeseries( warnings.warn( "asel argument to timeseries will be renamed to" "'atomgroup' in 3.0, see #3911", - category=DeprecationWarning, - ) + category=DeprecationWarning) if atomgroup: raise ValueError("Cannot provide both asel and atomgroup kwargs") atomgroup = asel @@ -334,14 +335,14 @@ def timeseries( if atomgroup is not None: if len(atomgroup) == 0: - raise ValueError("Timeseries requires at least one atom to analyze") + raise ValueError( + "Timeseries requires at least one atom to analyze") atom_numbers = list(atomgroup.indices) else: atom_numbers = list(range(self.n_atoms)) frames = self._file.readframes( - start, stop, step, order=order, indices=atom_numbers - ) + start, stop, step, order=order, indices=atom_numbers) return frames.xyz @@ -360,24 +361,21 @@ class DCDWriter(base.WriterBase): not match the expectations of other software. """ - - format = "DCD" + format = 'DCD' multiframe = True - flavor = "NAMD" - units = {"time": "AKMA", "length": "Angstrom"} - - def __init__( - self, - filename, - n_atoms, - convert_units=True, - step=1, - dt=1, - remarks="", - nsavc=1, - istart=0, - **kwargs - ): + flavor = 'NAMD' + units = {'time': 'AKMA', 'length': 'Angstrom'} + + def __init__(self, + filename, + n_atoms, + convert_units=True, + step=1, + dt=1, + remarks='', + nsavc=1, + istart=0, + **kwargs): """Parameters ---------- filename : str @@ -414,10 +412,10 @@ def __init__( if n_atoms is None: raise ValueError("n_atoms argument is required") self.n_atoms = n_atoms - self._file = DCDFile(self.filename, "w") + self._file = DCDFile(self.filename, 'w') self.step = step self.dt = dt - dt = mdaunits.convert(dt, "ps", self.units["time"]) + dt = mdaunits.convert(dt, 'ps', self.units['time']) delta = float(dt) / nsavc istart = istart if istart is not None else nsavc self._file.write_header( @@ -426,8 +424,7 @@ def __init__( nsavc=nsavc, delta=delta, is_periodic=1, - istart=istart, - ) + istart=istart) def _write_next_frame(self, ag): """Write information associated with ``obj`` at current frame into trajectory @@ -461,10 +458,8 @@ def _write_next_frame(self, ag): try: dimensions = ts.dimensions.copy() except AttributeError: - wmsg = ( - "No dimensions set for current frame, zeroed unitcell " - "will be written" - ) + wmsg = ('No dimensions set for current frame, zeroed unitcell ' + 'will be written') warnings.warn(wmsg) dimensions = np.zeros(6) diff --git a/package/MDAnalysis/coordinates/DLPoly.py b/package/MDAnalysis/coordinates/DLPoly.py index 622668564a..71297f978f 100644 --- a/package/MDAnalysis/coordinates/DLPoly.py +++ b/package/MDAnalysis/coordinates/DLPoly.py @@ -35,7 +35,7 @@ from ..lib import util from ..lib.util import cached, store_init_arguments -_DLPOLY_UNITS = {"length": "Angstrom", "velocity": "Angstrom/ps", "time": "ps"} +_DLPOLY_UNITS = {'length': 'Angstrom', 'velocity': 'Angstrom/ps', 'time': 'ps'} class ConfigReader(base.SingleFrameReaderBase): @@ -47,14 +47,13 @@ class ConfigReader(base.SingleFrameReaderBase): coordinates, velocities, and forces are no longer stored in 'F' memory layout, instead now using the numpy default of 'C'. """ - - format = "CONFIG" + format = 'CONFIG' units = _DLPOLY_UNITS def _read_first_frame(self): unitcell = np.zeros((3, 3), dtype=np.float32) - with open(self.filename, "r") as inf: + with open(self.filename, 'r') as inf: self.title = inf.readline().strip() levcfg, imcon, megatm = np.int64(inf.readline().split()[:3]) if not imcon == 0: @@ -114,9 +113,10 @@ def _read_first_frame(self): if has_forces: forces = forces[order] - ts = self.ts = self._Timestep( - self.n_atoms, velocities=has_vels, forces=has_forces, **self._ts_kwargs - ) + ts = self.ts = self._Timestep(self.n_atoms, + velocities=has_vels, + forces=has_forces, + **self._ts_kwargs) ts._pos = coords if has_vels: ts._velocities = velocities @@ -133,8 +133,7 @@ class HistoryReader(base.ReaderBase): .. versionadded:: 0.11.0 """ - - format = "HISTORY" + format = 'HISTORY' units = _DLPOLY_UNITS @store_init_arguments @@ -143,7 +142,7 @@ def __init__(self, filename, **kwargs): self._cache = {} # "private" file handle - self._file = util.anyopen(self.filename, "r") + self._file = util.anyopen(self.filename, 'r') self.title = self._file.readline().strip() header = np.int64(self._file.readline().split()[:3]) self._levcfg, self._imcon, self.n_atoms = header @@ -158,12 +157,10 @@ def __init__(self, filename, **kwargs): self._has_cell = False self._file.seek(rwnd) - self.ts = self._Timestep( - self.n_atoms, - velocities=self._has_vels, - forces=self._has_forces, - **self._ts_kwargs - ) + self.ts = self._Timestep(self.n_atoms, + velocities=self._has_vels, + forces=self._has_forces, + **self._ts_kwargs) self._read_next_timestep() def _read_next_timestep(self, ts=None): @@ -171,7 +168,7 @@ def _read_next_timestep(self, ts=None): ts = self.ts line = self._file.readline() # timestep line - if not line.startswith("timestep"): + if not line.startswith('timestep'): raise IOError if self._has_cell: @@ -179,7 +176,7 @@ def _read_next_timestep(self, ts=None): unitcell[0] = self._file.readline().split() unitcell[1] = self._file.readline().split() unitcell[2] = self._file.readline().split() - ts.dimensions = core.triclinic_box(*unitcell) + ts.dimensions = core.triclinic_box(*unitcell) # If ids are given, put them in here # and later sort by them @@ -223,17 +220,17 @@ def _read_frame(self, frame): return self._read_next_timestep() @property - @cached("n_frames") + @cached('n_frames') def n_frames(self): # Second line is traj_key, imcom, n_atoms, n_frames, n_records offsets = [] - with open(self.filename, "r") as f: + with open(self.filename, 'r') as f: f.readline() f.readline() position = f.tell() line = f.readline() - while line.startswith("timestep"): + while line.startswith('timestep'): offsets.append(position) if self._has_cell: f.readline() @@ -254,7 +251,7 @@ def n_frames(self): def _reopen(self): self.close() - self._file = open(self.filename, "r") + self._file = open(self.filename, 'r') self._file.readline() # header is 2 lines self._file.readline() self.ts.frame = -1 diff --git a/package/MDAnalysis/coordinates/DMS.py b/package/MDAnalysis/coordinates/DMS.py index 55df8a1a1c..04367f438d 100644 --- a/package/MDAnalysis/coordinates/DMS.py +++ b/package/MDAnalysis/coordinates/DMS.py @@ -106,12 +106,16 @@ def dict_factory(cursor, row): ) self.ts.frame = 0 # 0-based frame number - self.ts.dimensions = triclinic_box(unitcell["x"], unitcell["y"], unitcell["z"]) + self.ts.dimensions = triclinic_box( + unitcell["x"], unitcell["y"], unitcell["z"] + ) if self.convert_units: self.convert_pos_from_native(self.ts._pos) # in-place ! if self.ts.dimensions is not None: - self.convert_pos_from_native(self.ts.dimensions[:3]) # in-place ! + self.convert_pos_from_native( + self.ts.dimensions[:3] + ) # in-place ! if self.ts.has_velocities: # converts nm/ps to A/ps units self.convert_velocities_from_native(self.ts._velocities) diff --git a/package/MDAnalysis/coordinates/FHIAIMS.py b/package/MDAnalysis/coordinates/FHIAIMS.py index 48973e2963..3aff6d97f5 100644 --- a/package/MDAnalysis/coordinates/FHIAIMS.py +++ b/package/MDAnalysis/coordinates/FHIAIMS.py @@ -191,7 +191,9 @@ def _read_first_frame(self): if len(lattice_vectors) > 0: ts.dimensions = triclinic_box(*lattice_vectors) - ts.positions[relative] = np.matmul(ts.positions[relative], lattice_vectors) + ts.positions[relative] = np.matmul( + ts.positions[relative], lattice_vectors + ) if len(velocities) > 0: ts.velocities = velocities @@ -319,7 +321,9 @@ def _write_next_frame(self, obj): # all attributes could be infinite cycles! for atom_index, name in zip(range(ag.n_atoms), names): output_fhiaims.write( - self.fmt["xyz"].format(pos=positions[atom_index], name=name) + self.fmt["xyz"].format( + pos=positions[atom_index], name=name + ) ) if has_velocities: output_fhiaims.write( diff --git a/package/MDAnalysis/coordinates/GMS.py b/package/MDAnalysis/coordinates/GMS.py index b264146d22..6db412461d 100644 --- a/package/MDAnalysis/coordinates/GMS.py +++ b/package/MDAnalysis/coordinates/GMS.py @@ -75,7 +75,7 @@ class GMSReader(base.ReaderBase): format = "GMS" # these are assumed! - units = {"time": "ps", "length": "Angstrom"} + units = {'time': 'ps', 'length': 'Angstrom'} @store_init_arguments def __init__(self, outfilename, **kwargs): @@ -91,12 +91,12 @@ def __init__(self, outfilename, **kwargs): self._n_frames = None self._runtyp = None - self.ts = self._Timestep(0) # need for properties initial calculations + self.ts = self._Timestep(0) # need for properties initial calculations # update runtyp property self.runtyp - if not self.runtyp in ["optimize", "surface"]: - raise AttributeError("Wrong RUNTYP= " + self.runtyp) + if not self.runtyp in ['optimize', 'surface']: + raise AttributeError('Wrong RUNTYP= '+self.runtyp) self.ts = self._Timestep(self.n_atoms, **self._ts_kwargs) # update n_frames property @@ -108,7 +108,7 @@ def __init__(self, outfilename, **kwargs): @property def runtyp(self): """RUNTYP property of the GAMESS run""" - if self._runtyp is not None: # return cached value + if self._runtyp is not None: # return cached value return self._runtyp try: self._runtyp = self._determine_runtyp() @@ -120,7 +120,7 @@ def runtyp(self): def _determine_runtyp(self): with util.openany(self.filename) as out: for line in out: - m = re.match(r"^.*RUNTYP=([A-Z]+)\s+.*", line) + m = re.match(r'^.*RUNTYP=([A-Z]+)\s+.*', line) if m is not None: res = m.group(1).lower() break @@ -130,7 +130,7 @@ def _determine_runtyp(self): @property def n_atoms(self): """number of atoms in a frame""" - if self._n_atoms is not None: # return cached value + if self._n_atoms is not None: # return cached value return self._n_atoms try: self._n_atoms = self._read_out_natoms() @@ -142,7 +142,7 @@ def n_atoms(self): def _read_out_natoms(self): with util.openany(self.filename) as out: for line in out: - m = re.match(r"\s*TOTAL NUMBER OF ATOMS\s*=\s*([0-9]+)\s*", line) + m = re.match(r'\s*TOTAL NUMBER OF ATOMS\s*=\s*([0-9]+)\s*',line) if m is not None: res = int(m.group(1)) break @@ -151,7 +151,7 @@ def _read_out_natoms(self): @property def n_frames(self): - if self._n_frames is not None: # return cached value + if self._n_frames is not None: # return cached value return self._n_frames try: self._n_frames = self._read_out_n_frames() @@ -161,15 +161,15 @@ def n_frames(self): return self._n_frames def _read_out_n_frames(self): - if self.runtyp == "optimize": - trigger = re.compile(b"^.NSERCH=.*") - elif self.runtyp == "surface": - trigger = re.compile(b"^.COORD 1=.*") + if self.runtyp == 'optimize': + trigger = re.compile(b'^.NSERCH=.*') + elif self.runtyp == 'surface': + trigger = re.compile(b'^.COORD 1=.*') self._offsets = offsets = [] - with util.openany(self.filename, "rb") as out: + with util.openany(self.filename, 'rb') as out: line = True - while not line == b"": # while not EOF + while not line == b'': # while not EOF line = out.readline() if re.match(trigger, line): offsets.append(out.tell() - len(line)) @@ -196,16 +196,15 @@ def _read_next_timestep(self, ts=None): counter = 0 for line in self.outfile: - if self.runtyp == "optimize": - if (flag == 0) and (re.match(r"^.NSERCH=.*", line) is not None): + if self.runtyp == 'optimize': + if (flag == 0) and (re.match(r'^.NSERCH=.*', line) is not None): flag = 1 continue - if (flag == 1) and ( - re.match(r"^ COORDINATES OF ALL ATOMS ARE ", line) is not None - ): + if (flag == 1) and (re.match(r'^ COORDINATES OF ALL ATOMS ARE ',\ + line) is not None): flag = 2 continue - if (flag == 2) and (re.match(r"^\s*-+\s*", line) is not None): + if (flag == 2) and (re.match(r'^\s*-+\s*', line) is not None): flag = 3 continue if flag == 3 and counter < self.n_atoms: @@ -215,16 +214,13 @@ def _read_next_timestep(self, ts=None): z.append(float(words[4])) counter += 1 - elif self.runtyp == "surface": - if (flag == 0) and ( - re.match(r"^.COORD 1=\s*([-]?[0-9]+\.[0-9]+).*", line) is not None - ): + elif self.runtyp == 'surface': + if (flag == 0) and (re.match(\ + r'^.COORD 1=\s*([-]?[0-9]+\.[0-9]+).*', line) is not None): flag = 1 continue - if (flag == 1) and ( - re.match(r"^\s*HAS ENERGY VALUE\s*([-]?[0-9]+\.[0-9]+)\s*", line) - is not None - ): + if (flag == 1) and (re.match(\ + r'^\s*HAS ENERGY VALUE\s*([-]?[0-9]+\.[0-9]+)\s*', line) is not None): flag = 3 continue if flag == 3 and counter < self.n_atoms: @@ -236,12 +232,10 @@ def _read_next_timestep(self, ts=None): # stop when the cursor has reached the end of that block if counter == self._n_atoms: - ts._x[:] = ( - x # more efficient to do it this way to avoid re-creating the numpy arrays - ) + ts._x[:] = x # more efficient to do it this way to avoid re-creating the numpy arrays ts._y[:] = y ts._z[:] = z - # print ts.frame + #print ts.frame ts.frame += 1 return ts @@ -253,10 +247,10 @@ def _reopen(self): def open_trajectory(self): if self.outfile is not None: - raise IOError(errno.EALREADY, "GMS file already opened", self.filename) + raise IOError(errno.EALREADY, 'GMS file already opened', self.filename) if not os.path.exists(self.filename): # must check; otherwise might segmentation fault - raise IOError(errno.ENOENT, "GMS file not found", self.filename) + raise IOError(errno.ENOENT, 'GMS file not found', self.filename) self.outfile = util.anyopen(self.filename) diff --git a/package/MDAnalysis/coordinates/GRO.py b/package/MDAnalysis/coordinates/GRO.py index bd03d74cbe..f7eed70400 100644 --- a/package/MDAnalysis/coordinates/GRO.py +++ b/package/MDAnalysis/coordinates/GRO.py @@ -186,11 +186,13 @@ def _read_first_frame(self): first_atomline = grofile.readline() cs = first_atomline[25:].find(".") + 1 ts._pos[0] = [ - first_atomline[20 + cs * i : 20 + cs * (i + 1)] for i in range(3) + first_atomline[20 + cs * i : 20 + cs * (i + 1)] + for i in range(3) ] try: velocities[0] = [ - first_atomline[20 + cs * i : 20 + cs * (i + 1)] for i in range(3, 6) + first_atomline[20 + cs * i : 20 + cs * (i + 1)] + for i in range(3, 6) ] except ValueError: # Remember that we got this error @@ -204,13 +206,18 @@ def _read_first_frame(self): unitcell = np.float32(line.split()) except ValueError: # Try to parse floats with 5 digits if no spaces between values... - unitcell = np.float32(re.findall(r"(\d+\.\d{5})", line)) + unitcell = np.float32( + re.findall(r"(\d+\.\d{5})", line) + ) break - ts._pos[pos] = [line[20 + cs * i : 20 + cs * (i + 1)] for i in range(3)] + ts._pos[pos] = [ + line[20 + cs * i : 20 + cs * (i + 1)] for i in range(3) + ] try: velocities[pos] = [ - line[20 + cs * i : 20 + cs * (i + 1)] for i in range(3, 6) + line[20 + cs * i : 20 + cs * (i + 1)] + for i in range(3, 6) ] except ValueError: # Remember that we got this error @@ -220,7 +227,8 @@ def _read_first_frame(self): ts.velocities = velocities if missed_vel: warnings.warn( - "Not all velocities were present. " "Unset velocities set to zero." + "Not all velocities were present. " + "Unset velocities set to zero." ) self.ts.frame = 0 # 0-based frame number @@ -247,7 +255,9 @@ def _read_first_frame(self): if self.convert_units: self.convert_pos_from_native(self.ts._pos) # in-place ! if self.ts.dimensions is not None: - self.convert_pos_from_native(self.ts.dimensions[:3]) # in-place! + self.convert_pos_from_native( + self.ts.dimensions[:3] + ) # in-place! if self.ts.has_velocities: # converts nm/ps to A/ps units self.convert_velocities_from_native(self.ts._velocities) @@ -318,7 +328,9 @@ class GROWriter(base.WriterBase): "box_orthorhombic": "{box[0]:10.5f} {box[1]:9.5f} {box[2]:9.5f}\n", "box_triclinic": "{box[0]:10.5f} {box[4]:9.5f} {box[8]:9.5f} {box[1]:9.5f} {box[2]:9.5f} {box[3]:9.5f} {box[5]:9.5f} {box[6]:9.5f} {box[7]:9.5f}\n", } - fmt["xyz_v"] = fmt["xyz"][:-1] + "{vel[0]:8.4f}{vel[1]:8.4f}{vel[2]:8.4f}\n" + fmt["xyz_v"] = ( + fmt["xyz"][:-1] + "{vel[0]:8.4f}{vel[1]:8.4f}{vel[2]:8.4f}\n" + ) def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): """Set up a GROWriter with a precision of 3 decimal places. @@ -357,7 +369,9 @@ def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): self.n_atoms = n_atoms self.reindex = kwargs.pop("reindex", True) - self.convert_units = convert_units # convert length and time to base units + self.convert_units = ( + convert_units # convert length and time to base units + ) def write(self, obj): """Write selection at current trajectory frame to file. @@ -450,7 +464,9 @@ def write(self, obj): raise ValueError( "GRO files must have coordinate values between " "{0:.3f} and {1:.3f} nm: No file was written." - "".format(self.gro_coor_limits["min"], self.gro_coor_limits["max"]) + "".format( + self.gro_coor_limits["min"], self.gro_coor_limits["max"] + ) ) with util.openany(self.filename, "wt") as output_gro: @@ -464,7 +480,9 @@ def write(self, obj): for atom_index, resid, resname, name in zip( range(ag.n_atoms), resids, resnames, names ): - truncated_atom_index = util.ltruncate_int(atom_indices[atom_index], 5) + truncated_atom_index = util.ltruncate_int( + atom_indices[atom_index], 5 + ) truncated_resid = util.ltruncate_int(resid, 5) if has_velocities: output_gro.write( @@ -500,7 +518,9 @@ def write(self, obj): warnings.warn(wmsg) box = np.zeros(3) else: - box = self.convert_pos_to_native(ag.dimensions[:3], inplace=False) + box = self.convert_pos_to_native( + ag.dimensions[:3], inplace=False + ) # orthorhombic cell, only lengths along axes needed in gro output_gro.write(self.fmt["box_orthorhombic"].format(box=box)) else: @@ -509,5 +529,7 @@ def write(self, obj): except AttributeError: # for Timestep tri_dims = obj.triclinic_dimensions # full output - box = self.convert_pos_to_native(tri_dims.flatten(), inplace=False) + box = self.convert_pos_to_native( + tri_dims.flatten(), inplace=False + ) output_gro.write(self.fmt["box_triclinic"].format(box=box)) diff --git a/package/MDAnalysis/coordinates/H5MD.py b/package/MDAnalysis/coordinates/H5MD.py index 39b8301bd3..d92828687f 100644 --- a/package/MDAnalysis/coordinates/H5MD.py +++ b/package/MDAnalysis/coordinates/H5MD.py @@ -215,7 +215,6 @@ from ..exceptions import NoDataError from ..due import due, Doi from MDAnalysis.lib.util import store_init_arguments - try: import h5py except ImportError: @@ -226,7 +225,6 @@ class MockH5pyFile: pass - h5py = types.ModuleType("h5py") h5py.File = MockH5pyFile @@ -340,66 +338,65 @@ class H5MDReader(base.ReaderBase): """ - format = "H5MD" + format = 'H5MD' # units is defined as instance-level variable and set from the # H5MD file in __init__() below # This dictionary is used to translate H5MD units to MDAnalysis units. # (https://nongnu.org/h5md/modules/units.html) _unit_translation = { - "time": { - "ps": "ps", - "fs": "fs", - "ns": "ns", - "second": "s", - "sec": "s", - "s": "s", - "AKMA": "AKMA", - }, - "length": { - "Angstrom": "Angstrom", - "angstrom": "Angstrom", - "A": "Angstrom", - "nm": "nm", - "pm": "pm", - "fm": "fm", + 'time': { + 'ps': 'ps', + 'fs': 'fs', + 'ns': 'ns', + 'second': 's', + 'sec': 's', + 's': 's', + 'AKMA': 'AKMA', }, - "velocity": { - "Angstrom ps-1": "Angstrom/ps", - "A ps-1": "Angstrom/ps", - "Angstrom fs-1": "Angstrom/fs", - "A fs-1": "Angstrom/fs", - "Angstrom AKMA-1": "Angstrom/AKMA", - "A AKMA-1": "Angstrom/AKMA", - "nm ps-1": "nm/ps", - "nm ns-1": "nm/ns", - "pm ps-1": "pm/ps", - "m s-1": "m/s", + 'length': { + 'Angstrom': 'Angstrom', + 'angstrom': 'Angstrom', + 'A': 'Angstrom', + 'nm': 'nm', + 'pm': 'pm', + 'fm': 'fm', }, - "force": { - "kJ mol-1 Angstrom-1": "kJ/(mol*Angstrom)", - "kJ mol-1 nm-1": "kJ/(mol*nm)", - "Newton": "Newton", - "N": "N", - "J m-1": "J/m", - "kcal mol-1 Angstrom-1": "kcal/(mol*Angstrom)", - "kcal mol-1 A-1": "kcal/(mol*Angstrom)", + 'velocity': { + 'Angstrom ps-1': 'Angstrom/ps', + 'A ps-1': 'Angstrom/ps', + 'Angstrom fs-1': 'Angstrom/fs', + 'A fs-1': 'Angstrom/fs', + 'Angstrom AKMA-1': 'Angstrom/AKMA', + 'A AKMA-1': 'Angstrom/AKMA', + 'nm ps-1': 'nm/ps', + 'nm ns-1': 'nm/ns', + 'pm ps-1': 'pm/ps', + 'm s-1': 'm/s' }, + 'force': { + 'kJ mol-1 Angstrom-1': 'kJ/(mol*Angstrom)', + 'kJ mol-1 nm-1': 'kJ/(mol*nm)', + 'Newton': 'Newton', + 'N': 'N', + 'J m-1': 'J/m', + 'kcal mol-1 Angstrom-1': 'kcal/(mol*Angstrom)', + 'kcal mol-1 A-1': 'kcal/(mol*Angstrom)' + } } - @due.dcite( - Doi("10.25080/majora-1b6fd038-005"), - description="MDAnalysis trajectory reader/writer of the H5MD" "format", - path=__name__, - ) - @due.dcite( - Doi("10.1016/j.cpc.2014.01.018"), - description="Specifications of the H5MD standard", - path=__name__, - version="1.1", - ) + @due.dcite(Doi("10.25080/majora-1b6fd038-005"), + description="MDAnalysis trajectory reader/writer of the H5MD" + "format", path=__name__) + @due.dcite(Doi("10.1016/j.cpc.2014.01.018"), + description="Specifications of the H5MD standard", + path=__name__, version='1.1') @store_init_arguments - def __init__(self, filename, convert_units=True, driver=None, comm=None, **kwargs): + def __init__(self, filename, + convert_units=True, + driver=None, + comm=None, + **kwargs): """ Parameters ---------- @@ -445,49 +442,43 @@ def __init__(self, filename, convert_units=True, driver=None, comm=None, **kwarg # opened with parallel h5py/hdf5 enabled self._driver = driver self._comm = comm - if (self._comm is not None) and (self._driver != "mpio"): - raise ValueError( - "If MPI communicator object is used to open" - " h5md file, ``driver='mpio'`` must be passed." - ) + if (self._comm is not None) and (self._driver != 'mpio'): + raise ValueError("If MPI communicator object is used to open" + " h5md file, ``driver='mpio'`` must be passed.") self.open_trajectory() - if self._particle_group["box"].attrs["dimension"] != 3: - raise ValueError( - "MDAnalysis only supports 3-dimensional" " simulation boxes" - ) + if self._particle_group['box'].attrs['dimension'] != 3: + raise ValueError("MDAnalysis only supports 3-dimensional" + " simulation boxes") # _has dictionary used for checking whether h5md file has # 'position', 'velocity', or 'force' groups in the file - self._has = { - name: name in self._particle_group - for name in ("position", "velocity", "force") - } + self._has = {name: name in self._particle_group for + name in ('position', 'velocity', 'force')} # Gets some info about what settings the datasets were created with # from first available group for name, value in self._has.items(): if value: - dset = self._particle_group[f"{name}/value"] + dset = self._particle_group[f'{name}/value'] self.n_atoms = dset.shape[1] self.compression = dset.compression self.compression_opts = dset.compression_opts break else: - raise NoDataError( - "Provide at least a position, velocity" - " or force group in the h5md file." - ) - - self.ts = self._Timestep( - self.n_atoms, - positions=self.has_positions, - velocities=self.has_velocities, - forces=self.has_forces, - **self._ts_kwargs, - ) - - self.units = {"time": None, "length": None, "velocity": None, "force": None} + raise NoDataError("Provide at least a position, velocity" + " or force group in the h5md file.") + + self.ts = self._Timestep(self.n_atoms, + positions=self.has_positions, + velocities=self.has_velocities, + forces=self.has_forces, + **self._ts_kwargs) + + self.units = {'time': None, + 'length': None, + 'velocity': None, + 'force': None} self._set_translated_units() # fills units dictionary self._read_next_timestep() @@ -496,12 +487,11 @@ def _set_translated_units(self): and fills units dictionary""" # need this dictionary to associate 'position': 'length' - _group_unit_dict = { - "time": "time", - "position": "length", - "velocity": "velocity", - "force": "force", - } + _group_unit_dict = {'time': 'time', + 'position': 'length', + 'velocity': 'velocity', + 'force': 'force' + } for group, unit in _group_unit_dict.items(): self._translate_h5md_units(group, unit) @@ -515,52 +505,47 @@ def _translate_h5md_units(self, group, unit): # doing time unit separately because time has to fish for # first available parent group - either position, velocity, or force - if unit == "time": + if unit == 'time': for name, value in self._has.items(): if value: - if "unit" in self._particle_group[name]["time"].attrs: + if 'unit' in self._particle_group[name]['time'].attrs: try: - self.units["time"] = self._unit_translation["time"][ - self._particle_group[name]["time"].attrs["unit"] - ] + self.units['time'] = self._unit_translation[ + 'time'][self._particle_group[name][ + 'time'].attrs['unit']] break except KeyError: - raise RuntimeError( - errmsg.format( - unit, - self._particle_group[name]["time"].attrs["unit"], - ) - ) from None + raise RuntimeError(errmsg.format( + unit, self._particle_group[ + name]['time'].attrs['unit']) + ) from None else: if self._has[group]: - if "unit" in self._particle_group[group]["value"].attrs: + if 'unit' in self._particle_group[group]['value'].attrs: try: self.units[unit] = self._unit_translation[unit][ - self._particle_group[group]["value"].attrs["unit"] - ] + self._particle_group[group]['value'].attrs['unit']] except KeyError: - raise RuntimeError( - errmsg.format( - unit, self._particle_group[group]["value"].attrs["unit"] - ) - ) from None + raise RuntimeError(errmsg.format( + unit, self._particle_group[group][ + 'value'].attrs['unit']) + ) from None # if position group is not provided, can still get 'length' unit # from unitcell box - if (not self._has["position"]) and ("edges" in self._particle_group["box"]): - if "unit" in self._particle_group["box/edges/value"].attrs: + if (not self._has['position']) and ('edges' in self._particle_group['box']): + if 'unit' in self._particle_group['box/edges/value'].attrs: try: - self.units["length"] = self._unit_translation["length"][ - self._particle_group["box/edges/value"].attrs["unit"] - ] + self.units['length'] = self._unit_translation[ + 'length'][self._particle_group[ + 'box/edges/value' + ].attrs['unit']] except KeyError: - raise RuntimeError( - errmsg.format( - unit, - self._particle_group["box/edges/value"].attrs["unit"], - ) - ) from None + raise RuntimeError(errmsg.format(unit, + self._particle_group[ + 'box/edges/value'].attrs[ + 'unit'])) from None def _check_units(self, group, unit): """Raises error if no units are provided from H5MD file @@ -573,8 +558,8 @@ def _check_units(self, group, unit): " set to ``True``. MDAnalysis sets ``convert_units=True`` by default." " Set ``convert_units=False`` to load Universe without units." - if unit == "time": - if self.units["time"] is None: + if unit == 'time': + if self.units['time'] is None: raise ValueError(errmsg) else: @@ -591,18 +576,16 @@ def _format_hint(thing): @staticmethod def parse_n_atoms(filename): - with h5py.File(filename, "r") as f: - for group in f["particles/trajectory"]: - if group in ("position", "velocity", "force"): - n_atoms = f[f"particles/trajectory/{group}/value"].shape[1] + with h5py.File(filename, 'r') as f: + for group in f['particles/trajectory']: + if group in ('position', 'velocity', 'force'): + n_atoms = f[f'particles/trajectory/{group}/value'].shape[1] return n_atoms - raise NoDataError( - "Could not construct minimal topology from the " - "H5MD trajectory file, as it did not contain a " - "'position', 'velocity', or 'force' group. " - "You must include a topology file." - ) + raise NoDataError("Could not construct minimal topology from the " + "H5MD trajectory file, as it did not contain a " + "'position', 'velocity', or 'force' group. " + "You must include a topology file.") def open_trajectory(self): """opens the trajectory file using h5py library""" @@ -613,41 +596,38 @@ def open_trajectory(self): else: if self._comm is not None: # can only pass comm argument to h5py.File if driver='mpio' - assert self._driver == "mpio" - self._file = H5PYPicklable( - name=self.filename, # pragma: no cover - mode="r", - driver=self._driver, - comm=self._comm, - ) + assert self._driver == 'mpio' + self._file = H5PYPicklable(name=self.filename, # pragma: no cover + mode='r', + driver=self._driver, + comm=self._comm) else: - self._file = H5PYPicklable( - name=self.filename, mode="r", driver=self._driver - ) + self._file = H5PYPicklable(name=self.filename, + mode='r', + driver=self._driver) # pulls first key out of 'particles' # allows for arbitrary name of group1 in 'particles' - self._particle_group = self._file["particles"][list(self._file["particles"])[0]] + self._particle_group = self._file['particles'][ + list(self._file['particles'])[0]] @property def n_frames(self): """number of frames in trajectory""" for name, value in self._has.items(): if value: - return self._particle_group[name]["value"].shape[0] + return self._particle_group[name]['value'].shape[0] def _read_frame(self, frame): """reads data from h5md file and copies to current timestep""" try: for name, value in self._has.items(): if value: - _ = self._particle_group[name]["step"][frame] + _ = self._particle_group[name]['step'][frame] break else: - raise NoDataError( - "Provide at least a position, velocity" - " or force group in the h5md file." - ) + raise NoDataError("Provide at least a position, velocity" + " or force group in the h5md file.") except (ValueError, IndexError): raise IOError from None @@ -679,12 +659,12 @@ def _read_frame(self, frame): # set the timestep positions, velocities, and forces with # current frame dataset - if self._has["position"]: - self._read_dataset_into_ts("position", ts.positions) - if self._has["velocity"]: - self._read_dataset_into_ts("velocity", ts.velocities) - if self._has["force"]: - self._read_dataset_into_ts("force", ts.forces) + if self._has['position']: + self._read_dataset_into_ts('position', ts.positions) + if self._has['velocity']: + self._read_dataset_into_ts('velocity', ts.velocities) + if self._has['force']: + self._read_dataset_into_ts('force', ts.forces) if self.convert_units: self._convert_units() @@ -699,9 +679,9 @@ def _copy_to_data(self): try: # if has value as subkey read directly into data if "value" in self._file["observables"][key]: - self.ts.data[key] = self._file["observables"][key]["value"][ - self._frame - ] + self.ts.data[key] = self._file["observables"][key][ + "value" + ][self._frame] # if value is not a subkey, read dict of subkeys else: for subkey in self._file["observables"][key].keys(): @@ -719,35 +699,33 @@ def _copy_to_data(self): # pulls 'time' and 'step' out of first available parent group for name, value in self._has.items(): if value: - if "time" in self._particle_group[name]: - self.ts.time = self._particle_group[name]["time"][self._frame] + if 'time' in self._particle_group[name]: + self.ts.time = self._particle_group[name][ + 'time'][self._frame] break for name, value in self._has.items(): if value: - if "step" in self._particle_group[name]: - self.ts.data["step"] = self._particle_group[name]["step"][ - self._frame - ] + if 'step' in self._particle_group[name]: + self.ts.data['step'] = self._particle_group[name][ + 'step'][self._frame] break def _read_dataset_into_ts(self, dataset, attribute): """reads position, velocity, or force dataset array at current frame into corresponding ts attribute""" - n_atoms_now = self._particle_group[f"{dataset}/value"][self._frame].shape[0] + n_atoms_now = self._particle_group[f'{dataset}/value'][ + self._frame].shape[0] if n_atoms_now != self.n_atoms: - raise ValueError( - f"Frame {self._frame} of the {dataset} dataset" - f" has {n_atoms_now} atoms but the initial frame" - " of either the postion, velocity, or force" - f" dataset had {self.n_atoms} atoms." - " MDAnalysis is unable to deal" - " with variable topology!" - ) - - self._particle_group[f"{dataset}/value"].read_direct( - attribute, source_sel=np.s_[self._frame, :] - ) + raise ValueError(f"Frame {self._frame} of the {dataset} dataset" + f" has {n_atoms_now} atoms but the initial frame" + " of either the postion, velocity, or force" + f" dataset had {self.n_atoms} atoms." + " MDAnalysis is unable to deal" + " with variable topology!") + + self._particle_group[f'{dataset}/value'].read_direct( + attribute, source_sel=np.s_[self._frame, :]) def _convert_units(self): """converts time, position, velocity, and force values if they @@ -758,16 +736,16 @@ def _convert_units(self): self.ts.time = self.convert_time_from_native(self.ts.time) - if "edges" in self._particle_group["box"] and self.ts.dimensions is not None: + if 'edges' in self._particle_group['box'] and self.ts.dimensions is not None: self.convert_pos_from_native(self.ts.dimensions[:3]) - if self._has["position"]: + if self._has['position']: self.convert_pos_from_native(self.ts.positions) - if self._has["velocity"]: + if self._has['velocity']: self.convert_velocities_from_native(self.ts.velocities) - if self._has["force"]: + if self._has['force']: self.convert_forces_from_native(self.ts.forces) def _read_next_timestep(self): @@ -824,49 +802,50 @@ def Writer(self, filename, n_atoms=None, **kwargs): """ if n_atoms is None: n_atoms = self.n_atoms - kwargs.setdefault("driver", self._driver) - kwargs.setdefault("compression", self.compression) - kwargs.setdefault("compression_opts", self.compression_opts) - kwargs.setdefault("positions", self.has_positions) - kwargs.setdefault("velocities", self.has_velocities) - kwargs.setdefault("forces", self.has_forces) + kwargs.setdefault('driver', self._driver) + kwargs.setdefault('compression', self.compression) + kwargs.setdefault('compression_opts', self.compression_opts) + kwargs.setdefault('positions', self.has_positions) + kwargs.setdefault('velocities', self.has_velocities) + kwargs.setdefault('forces', self.has_forces) return H5MDWriter(filename, n_atoms, **kwargs) @property def has_positions(self): """``True`` if 'position' group is in trajectory.""" - return self._has["position"] + return self._has['position'] @has_positions.setter def has_positions(self, value: bool): - self._has["position"] = value + self._has['position'] = value @property def has_velocities(self): """``True`` if 'velocity' group is in trajectory.""" - return self._has["velocity"] + return self._has['velocity'] @has_velocities.setter def has_velocities(self, value: bool): - self._has["velocity"] = value + self._has['velocity'] = value @property def has_forces(self): """``True`` if 'force' group is in trajectory.""" - return self._has["force"] + return self._has['force'] @has_forces.setter def has_forces(self, value: bool): - self._has["force"] = value + self._has['force'] = value def __getstate__(self): state = self.__dict__.copy() - del state["_particle_group"] + del state['_particle_group'] return state def __setstate__(self, state): self.__dict__ = state - self._particle_group = self._file["particles"][list(self._file["particles"])[0]] + self._particle_group = self._file['particles'][ + list(self._file['particles'])[0]] class H5MDWriter(base.WriterBase): @@ -1046,11 +1025,11 @@ class H5MDWriter(base.WriterBase): """ - format = "H5MD" + format = 'H5MD' multiframe = True #: These variables are not written from :attr:`Timestep.data` #: dictionary to the observables group in the H5MD file - data_blacklist = ["step", "time", "dt"] + data_blacklist = ['step', 'time', 'dt'] #: currently written version of the file format H5MD_VERSION = (1, 1) @@ -1058,80 +1037,54 @@ class H5MDWriter(base.WriterBase): # This dictionary is used to translate MDAnalysis units to H5MD units. # (https://nongnu.org/h5md/modules/units.html) _unit_translation_dict = { - "time": { - "ps": "ps", - "fs": "fs", - "ns": "ns", - "second": "s", - "sec": "s", - "s": "s", - "AKMA": "AKMA", - }, - "length": { - "Angstrom": "Angstrom", - "angstrom": "Angstrom", - "A": "Angstrom", - "nm": "nm", - "pm": "pm", - "fm": "fm", - }, - "velocity": { - "Angstrom/ps": "Angstrom ps-1", - "A/ps": "Angstrom ps-1", - "Angstrom/fs": "Angstrom fs-1", - "A/fs": "Angstrom fs-1", - "Angstrom/AKMA": "Angstrom AKMA-1", - "A/AKMA": "Angstrom AKMA-1", - "nm/ps": "nm ps-1", - "nm/ns": "nm ns-1", - "pm/ps": "pm ps-1", - "m/s": "m s-1", - }, - "force": { - "kJ/(mol*Angstrom)": "kJ mol-1 Angstrom-1", - "kJ/(mol*nm)": "kJ mol-1 nm-1", - "Newton": "Newton", - "N": "N", - "J/m": "J m-1", - "kcal/(mol*Angstrom)": "kcal mol-1 Angstrom-1", - "kcal/(mol*A)": "kcal mol-1 Angstrom-1", - }, - } - - @due.dcite( - Doi("10.25080/majora-1b6fd038-005"), - description="MDAnalysis trajectory reader/writer of the H5MD" "format", - path=__name__, - ) - @due.dcite( - Doi("10.1016/j.cpc.2014.01.018"), - description="Specifications of the H5MD standard", - path=__name__, - version="1.1", - ) - def __init__( - self, - filename, - n_atoms, - n_frames=None, - driver=None, - convert_units=True, - chunks=None, - compression=None, - compression_opts=None, - positions=True, - velocities=True, - forces=True, - timeunit=None, - lengthunit=None, - velocityunit=None, - forceunit=None, - author="N/A", - author_email=None, - creator="MDAnalysis", - creator_version=mda.__version__, - **kwargs, - ): + 'time': { + 'ps': 'ps', + 'fs': 'fs', + 'ns': 'ns', + 'second': 's', + 'sec': 's', + 's': 's', + 'AKMA': 'AKMA'}, + 'length': { + 'Angstrom': 'Angstrom', + 'angstrom': 'Angstrom', + 'A': 'Angstrom', + 'nm': 'nm', + 'pm': 'pm', + 'fm': 'fm'}, + 'velocity': { + 'Angstrom/ps': 'Angstrom ps-1', + 'A/ps': 'Angstrom ps-1', + 'Angstrom/fs': 'Angstrom fs-1', + 'A/fs': 'Angstrom fs-1', + 'Angstrom/AKMA': 'Angstrom AKMA-1', + 'A/AKMA': 'Angstrom AKMA-1', + 'nm/ps': 'nm ps-1', + 'nm/ns': 'nm ns-1', + 'pm/ps': 'pm ps-1', + 'm/s': 'm s-1'}, + 'force': { + 'kJ/(mol*Angstrom)': 'kJ mol-1 Angstrom-1', + 'kJ/(mol*nm)': 'kJ mol-1 nm-1', + 'Newton': 'Newton', + 'N': 'N', + 'J/m': 'J m-1', + 'kcal/(mol*Angstrom)': 'kcal mol-1 Angstrom-1', + 'kcal/(mol*A)': 'kcal mol-1 Angstrom-1'}} + + @due.dcite(Doi("10.25080/majora-1b6fd038-005"), + description="MDAnalysis trajectory reader/writer of the H5MD" + "format", path=__name__) + @due.dcite(Doi("10.1016/j.cpc.2014.01.018"), + description="Specifications of the H5MD standard", + path=__name__, version='1.1') + def __init__(self, filename, n_atoms, n_frames=None, driver=None, + convert_units=True, chunks=None, compression=None, + compression_opts=None, positions=True, velocities=True, + forces=True, timeunit=None, lengthunit=None, + velocityunit=None, forceunit=None, author='N/A', + author_email=None, creator='MDAnalysis', + creator_version=mda.__version__, **kwargs): if not HAS_H5PY: raise RuntimeError("H5MDWriter: Please install h5py") @@ -1139,19 +1092,15 @@ def __init__( if n_atoms == 0: raise ValueError("H5MDWriter: no atoms in output trajectory") self._driver = driver - if self._driver == "mpio": - raise ValueError( - "H5MDWriter: parallel writing with MPI I/O " - "is not currently supported." - ) + if self._driver == 'mpio': + raise ValueError("H5MDWriter: parallel writing with MPI I/O " + "is not currently supported.") self.n_atoms = n_atoms self.n_frames = n_frames self.chunks = (1, n_atoms, 3) if chunks is None else chunks if self.chunks is False and self.n_frames is None: - raise ValueError( - "H5MDWriter must know how many frames will be " - "written if ``chunks=False``." - ) + raise ValueError("H5MDWriter must know how many frames will be " + "written if ``chunks=False``.") self.contiguous = self.chunks is False and self.n_frames is not None self.compression = compression self.compression_opts = compression_opts @@ -1165,20 +1114,16 @@ def __init__( self._write_positions = positions self._write_velocities = velocities self._write_forces = forces - if not any( - [self._write_positions, self._write_velocities, self._write_velocities] - ): - raise ValueError( - "At least one of positions, velocities, or " - "forces must be set to ``True``." - ) - - self._new_units = { - "time": timeunit, - "length": lengthunit, - "velocity": velocityunit, - "force": forceunit, - } + if not any([self._write_positions, + self._write_velocities, + self._write_velocities]): + raise ValueError("At least one of positions, velocities, or " + "forces must be set to ``True``.") + + self._new_units = {'time': timeunit, + 'length': lengthunit, + 'velocity': velocityunit, + 'force': forceunit} # Pull out various keywords to store metadata in 'h5md' group self.author = author @@ -1207,9 +1152,8 @@ def _write_next_frame(self, ag): raise TypeError(errmsg) from None if ts.n_atoms != self.n_atoms: - raise IOError( - "H5MDWriter: Timestep does not have" " the correct number of atoms" - ) + raise IOError("H5MDWriter: Timestep does not have" + " the correct number of atoms") # This should only be called once when first timestep is read. if self.h5md_file is None: @@ -1240,25 +1184,21 @@ def _determine_units(self, ag): for key, value in self._new_units.items(): if value is not None: if value not in self._unit_translation_dict[key]: - raise ValueError( - f"{value} is not a unit recognized by" - " MDAnalysis. Allowed units are:" - f" {self._unit_translation_dict.keys()}" - " For more information on units, see" - " `MDAnalysis units`_." - ) + raise ValueError(f"{value} is not a unit recognized by" + " MDAnalysis. Allowed units are:" + f" {self._unit_translation_dict.keys()}" + " For more information on units, see" + " `MDAnalysis units`_.") else: self.units[key] = self._new_units[key] if self.convert_units: # check if all units are None if not any(self.units.values()): - raise ValueError( - "The trajectory has no units, but " - "`convert_units` is set to ``True`` by " - "default in MDAnalysis. To write the file " - "with no units, set ``convert_units=False``." - ) + raise ValueError("The trajectory has no units, but " + "`convert_units` is set to ``True`` by " + "default in MDAnalysis. To write the file " + "with no units, set ``convert_units=False``.") def _open_file(self): """Opens file with `H5PY`_ library and fills in metadata from kwargs. @@ -1267,18 +1207,20 @@ def _open_file(self): """ - self.h5md_file = h5py.File(name=self.filename, mode="w", driver=self._driver) + self.h5md_file = h5py.File(name=self.filename, + mode='w', + driver=self._driver) # fill in H5MD metadata from kwargs - self.h5md_file.require_group("h5md") - self.h5md_file["h5md"].attrs["version"] = np.array(self.H5MD_VERSION) - self.h5md_file["h5md"].require_group("author") - self.h5md_file["h5md/author"].attrs["name"] = self.author + self.h5md_file.require_group('h5md') + self.h5md_file['h5md'].attrs['version'] = np.array(self.H5MD_VERSION) + self.h5md_file['h5md'].require_group('author') + self.h5md_file['h5md/author'].attrs['name'] = self.author if self.author_email is not None: - self.h5md_file["h5md/author"].attrs["email"] = self.author_email - self.h5md_file["h5md"].require_group("creator") - self.h5md_file["h5md/creator"].attrs["name"] = self.creator - self.h5md_file["h5md/creator"].attrs["version"] = self.creator_version + self.h5md_file['h5md/author'].attrs['email'] = self.author_email + self.h5md_file['h5md'].require_group('creator') + self.h5md_file['h5md/creator'].attrs['name'] = self.creator + self.h5md_file['h5md/creator'].attrs['version'] = self.creator_version def _initialize_hdf5_datasets(self, ts): """initializes all datasets that will be written to by @@ -1300,61 +1242,57 @@ def _initialize_hdf5_datasets(self, ts): # ask the parent file if it has positions, velocities, and forces # if prompted by the writer with the self._write_* attributes - self._has = { - group: ( - getattr(ts, f"has_{attr}") if getattr(self, f"_write_{attr}") else False - ) - for group, attr in zip( - ("position", "velocity", "force"), ("positions", "velocities", "forces") - ) - } + self._has = {group: getattr(ts, f'has_{attr}') + if getattr(self, f'_write_{attr}') + else False for group, attr in zip( + ('position', 'velocity', 'force'), + ('positions', 'velocities', 'forces'))} # initialize trajectory group - self.h5md_file.require_group("particles").require_group("trajectory") - self._traj = self.h5md_file["particles/trajectory"] + self.h5md_file.require_group('particles').require_group('trajectory') + self._traj = self.h5md_file['particles/trajectory'] self.data_keys = [ - key for key in ts.data.keys() if key not in self.data_blacklist - ] + key for key in ts.data.keys() if key not in self.data_blacklist] if self.data_keys: - self._obsv = self.h5md_file.require_group("observables") + self._obsv = self.h5md_file.require_group('observables') # box group is required for every group in 'particles' - self._traj.require_group("box") - self._traj["box"].attrs["dimension"] = 3 + self._traj.require_group('box') + self._traj['box'].attrs['dimension'] = 3 if ts.dimensions is not None and np.all(ts.dimensions > 0): - self._traj["box"].attrs["boundary"] = 3 * ["periodic"] - self._traj["box"].require_group("edges") - self._edges = self._traj.require_dataset( - "box/edges/value", - shape=(0, 3, 3), - maxshape=(None, 3, 3), - dtype=np.float32, - ) - self._step = self._traj.require_dataset( - "box/edges/step", shape=(0,), maxshape=(None,), dtype=np.int32 - ) - self._time = self._traj.require_dataset( - "box/edges/time", shape=(0,), maxshape=(None,), dtype=np.float32 - ) - self._set_attr_unit(self._edges, "length") - self._set_attr_unit(self._time, "time") + self._traj['box'].attrs['boundary'] = 3*['periodic'] + self._traj['box'].require_group('edges') + self._edges = self._traj.require_dataset('box/edges/value', + shape=(0, 3, 3), + maxshape=(None, 3, 3), + dtype=np.float32) + self._step = self._traj.require_dataset('box/edges/step', + shape=(0,), + maxshape=(None,), + dtype=np.int32) + self._time = self._traj.require_dataset('box/edges/time', + shape=(0,), + maxshape=(None,), + dtype=np.float32) + self._set_attr_unit(self._edges, 'length') + self._set_attr_unit(self._time, 'time') else: # if no box, boundary attr must be "none" according to H5MD - self._traj["box"].attrs["boundary"] = 3 * ["none"] + self._traj['box'].attrs['boundary'] = 3*['none'] self._create_step_and_time_datasets() if self.has_positions: - self._create_trajectory_dataset("position") - self._pos = self._traj["position/value"] - self._set_attr_unit(self._pos, "length") + self._create_trajectory_dataset('position') + self._pos = self._traj['position/value'] + self._set_attr_unit(self._pos, 'length') if self.has_velocities: - self._create_trajectory_dataset("velocity") - self._vel = self._traj["velocity/value"] - self._set_attr_unit(self._vel, "velocity") + self._create_trajectory_dataset('velocity') + self._vel = self._traj['velocity/value'] + self._set_attr_unit(self._vel, 'velocity') if self.has_forces: - self._create_trajectory_dataset("force") - self._force = self._traj["force/value"] - self._set_attr_unit(self._force, "force") + self._create_trajectory_dataset('force') + self._force = self._traj['force/value'] + self._set_attr_unit(self._force, 'force') # intialize observable datasets from ts.data dictionary that # are NOT in self.data_blacklist @@ -1383,13 +1321,15 @@ def _create_step_and_time_datasets(self): for group, value in self._has.items(): if value: - self._step = self._traj.require_dataset( - f"{group}/step", shape=(0,), maxshape=(None,), dtype=np.int32 - ) - self._time = self._traj.require_dataset( - f"{group}/time", shape=(0,), maxshape=(None,), dtype=np.float32 - ) - self._set_attr_unit(self._time, "time") + self._step = self._traj.require_dataset(f'{group}/step', + shape=(0,), + maxshape=(None,), + dtype=np.int32) + self._time = self._traj.require_dataset(f'{group}/time', + shape=(0,), + maxshape=(None,), + dtype=np.float32) + self._set_attr_unit(self._time, 'time') break def _create_trajectory_dataset(self, group): @@ -1406,19 +1346,17 @@ def _create_trajectory_dataset(self, group): chunks = None if self.contiguous else self.chunks self._traj.require_group(group) - self._traj.require_dataset( - f"{group}/value", - shape=shape, - maxshape=maxshape, - dtype=np.float32, - chunks=chunks, - compression=self.compression, - compression_opts=self.compression_opts, - ) - if "step" not in self._traj[group]: - self._traj[f"{group}/step"] = self._step - if "time" not in self._traj[group]: - self._traj[f"{group}/time"] = self._time + self._traj.require_dataset(f'{group}/value', + shape=shape, + maxshape=maxshape, + dtype=np.float32, + chunks=chunks, + compression=self.compression, + compression_opts=self.compression_opts) + if 'step' not in self._traj[group]: + self._traj[f'{group}/step'] = self._step + if 'time' not in self._traj[group]: + self._traj[f'{group}/time'] = self._time def _create_observables_dataset(self, group, data): """helper function to initialize a dataset for each observable""" @@ -1426,16 +1364,14 @@ def _create_observables_dataset(self, group, data): self._obsv.require_group(group) # guarantee ints and floats have a shape () data = np.asarray(data) - self._obsv.require_dataset( - f"{group}/value", - shape=(0,) + data.shape, - maxshape=(None,) + data.shape, - dtype=data.dtype, - ) - if "step" not in self._obsv[group]: - self._obsv[f"{group}/step"] = self._step - if "time" not in self._obsv[group]: - self._obsv[f"{group}/time"] = self._time + self._obsv.require_dataset(f'{group}/value', + shape=(0,) + data.shape, + maxshape=(None,) + data.shape, + dtype=data.dtype) + if 'step' not in self._obsv[group]: + self._obsv[f'{group}/step'] = self._step + if 'time' not in self._obsv[group]: + self._obsv[f'{group}/time'] = self._time def _set_attr_unit(self, dset, unit): """helper function to set a 'unit' attribute for an HDF5 dataset""" @@ -1443,7 +1379,7 @@ def _set_attr_unit(self, dset, unit): if self.units[unit] is None: return - dset.attrs["unit"] = self._unit_translation_dict[unit][self.units[unit]] + dset.attrs['unit'] = self._unit_translation_dict[unit][self.units[unit]] def _write_next_timestep(self, ts): """Write coordinates and unitcell information to H5MD file. @@ -1470,43 +1406,42 @@ def _write_next_timestep(self, ts): # sampled, therefore ts.data['step'] is the most appropriate value # to use. However, step is also necessary in H5MD to allow # temporal matching of the data, so ts.frame is used as an alternative - self._step.resize(self._step.shape[0] + 1, axis=0) + self._step.resize(self._step.shape[0]+1, axis=0) try: - self._step[i] = ts.data["step"] - except KeyError: + self._step[i] = ts.data['step'] + except(KeyError): self._step[i] = ts.frame - if len(self._step) > 1 and self._step[i] < self._step[i - 1]: - raise ValueError( - "The H5MD standard dictates that the step " - "dataset must increase monotonically in value." - ) + if len(self._step) > 1 and self._step[i] < self._step[i-1]: + raise ValueError("The H5MD standard dictates that the step " + "dataset must increase monotonically in value.") # the dataset.resize() method should work with any chunk shape - self._time.resize(self._time.shape[0] + 1, axis=0) + self._time.resize(self._time.shape[0]+1, axis=0) self._time[i] = ts.time - if "edges" in self._traj["box"]: - self._edges.resize(self._edges.shape[0] + 1, axis=0) - self._edges.write_direct(ts.triclinic_dimensions, dest_sel=np.s_[i, :]) + if 'edges' in self._traj['box']: + self._edges.resize(self._edges.shape[0]+1, axis=0) + self._edges.write_direct(ts.triclinic_dimensions, + dest_sel=np.s_[i, :]) # These datasets are not resized if n_frames was provided as an # argument, as they were initialized with their full size. if self.has_positions: if self.n_frames is None: - self._pos.resize(self._pos.shape[0] + 1, axis=0) + self._pos.resize(self._pos.shape[0]+1, axis=0) self._pos.write_direct(ts.positions, dest_sel=np.s_[i, :]) if self.has_velocities: if self.n_frames is None: - self._vel.resize(self._vel.shape[0] + 1, axis=0) + self._vel.resize(self._vel.shape[0]+1, axis=0) self._vel.write_direct(ts.velocities, dest_sel=np.s_[i, :]) if self.has_forces: if self.n_frames is None: - self._force.resize(self._force.shape[0] + 1, axis=0) + self._force.resize(self._force.shape[0]+1, axis=0) self._force.write_direct(ts.forces, dest_sel=np.s_[i, :]) if self.data_keys: for key in self.data_keys: - obs = self._obsv[f"{key}/value"] - obs.resize(obs.shape[0] + 1, axis=0) + obs = self._obsv[f'{key}/value'] + obs.resize(obs.shape[0]+1, axis=0) obs[i] = ts.data[key] if self.convert_units: @@ -1519,34 +1454,34 @@ def _convert_dataset_with_units(self, i): # Note: simply doing convert_pos_to_native(self._pos[-1]) does not # actually change the values in the dataset, so assignment required - if self.units["time"] is not None: + if self.units['time'] is not None: self._time[i] = self.convert_time_to_native(self._time[i]) - if self.units["length"] is not None: - if self._has["position"]: + if self.units['length'] is not None: + if self._has['position']: self._pos[i] = self.convert_pos_to_native(self._pos[i]) - if "edges" in self._traj["box"]: + if 'edges' in self._traj['box']: self._edges[i] = self.convert_pos_to_native(self._edges[i]) - if self._has["velocity"]: - if self.units["velocity"] is not None: + if self._has['velocity']: + if self.units['velocity'] is not None: self._vel[i] = self.convert_velocities_to_native(self._vel[i]) - if self._has["force"]: - if self.units["force"] is not None: + if self._has['force']: + if self.units['force'] is not None: self._force[i] = self.convert_forces_to_native(self._force[i]) @property def has_positions(self): """``True`` if writer is writing positions from Timestep.""" - return self._has["position"] + return self._has['position'] @property def has_velocities(self): """``True`` if writer is writing velocities from Timestep.""" - return self._has["velocity"] + return self._has['velocity'] @property def has_forces(self): """``True`` if writer is writing forces from Timestep.""" - return self._has["force"] + return self._has['force'] class H5PYPicklable(h5py.File): @@ -1605,16 +1540,18 @@ def __getstate__(self): # from self and pickle MPI.Comm object. Parallel driver is excluded # from test because h5py calls for an MPI configuration when driver is # 'mpio', so this will need to be patched in the test function. - if driver == "mpio": # pragma: no cover - raise TypeError( - "Parallel pickling of `h5py.File` with" # pragma: no cover - " 'mpio' driver is currently not supported." - ) + if driver == 'mpio': # pragma: no cover + raise TypeError("Parallel pickling of `h5py.File` with" # pragma: no cover + " 'mpio' driver is currently not supported.") - return {"name": self.filename, "mode": self.mode, "driver": driver} + return {'name': self.filename, + 'mode': self.mode, + 'driver': driver} def __setstate__(self, state): - self.__init__(name=state["name"], mode=state["mode"], driver=state["driver"]) + self.__init__(name=state['name'], + mode=state['mode'], + driver=state['driver']) def __getnewargs__(self): """Override the h5py getnewargs to skip its error message""" diff --git a/package/MDAnalysis/coordinates/LAMMPS.py b/package/MDAnalysis/coordinates/LAMMPS.py index d0fc0115bc..a8584bb3f1 100644 --- a/package/MDAnalysis/coordinates/LAMMPS.py +++ b/package/MDAnalysis/coordinates/LAMMPS.py @@ -221,7 +221,9 @@ def __init__(self, dcdfilename, **kwargs): ) ) except KeyError: - raise ValueError("LAMMPS DCDReader: unknown unit {0!r}".format(unit)) + raise ValueError( + "LAMMPS DCDReader: unknown unit {0!r}".format(unit) + ) super(DCDReader, self).__init__(dcdfilename, **kwargs) @@ -254,7 +256,9 @@ def _read_first_frame(self): if self.convert_units: self.convert_pos_from_native(self.ts._pos) # in-place ! try: - self.convert_velocities_from_native(self.ts._velocities) # in-place ! + self.convert_velocities_from_native( + self.ts._velocities + ) # in-place ! except AttributeError: pass @@ -329,7 +333,9 @@ def _write_atoms(self, atoms, data): moltags = data.get("molecule_tag", np.zeros(len(atoms), dtype=int)) if self.convert_units: - coordinates = self.convert_pos_to_native(atoms.positions, inplace=False) + coordinates = self.convert_pos_to_native( + atoms.positions, inplace=False + ) if has_charges: for index, moltag, atype, charge, coords in zip( @@ -337,21 +343,26 @@ def _write_atoms(self, atoms, data): ): x, y, z = coords self.f.write( - f"{index:d} {moltag:d} {atype:d} {charge:f}" f" {x:f} {y:f} {z:f}\n" + f"{index:d} {moltag:d} {atype:d} {charge:f}" + f" {x:f} {y:f} {z:f}\n" ) else: for index, moltag, atype, coords in zip( indices, moltags, types, coordinates ): x, y, z = coords - self.f.write(f"{index:d} {moltag:d} {atype:d}" f" {x:f} {y:f} {z:f}\n") + self.f.write( + f"{index:d} {moltag:d} {atype:d}" f" {x:f} {y:f} {z:f}\n" + ) def _write_velocities(self, atoms): self.f.write("\n") self.f.write("Velocities\n") self.f.write("\n") indices = atoms.indices + 1 - velocities = self.convert_velocities_to_native(atoms.velocities, inplace=False) + velocities = self.convert_velocities_to_native( + atoms.velocities, inplace=False + ) for index, vel in zip(indices, velocities): self.f.write( "{i:d} {x:f} {y:f} {z:f}\n".format( @@ -368,7 +379,9 @@ def _write_masses(self, atoms): for atype in range(1, max_type + 1): # search entire universe for mass info, not just writing selection masses = set( - atoms.universe.atoms.select_atoms("type {:d}".format(atype)).masses + atoms.universe.atoms.select_atoms( + "type {:d}".format(atype) + ).masses ) if len(masses) == 0: mass_dict[atype] = 1.0 @@ -461,7 +474,10 @@ def write(self, selection, frame=None): try: atoms.types.astype(np.int32) except ValueError: - errmsg = "LAMMPS.DATAWriter: atom types must be convertible to " "integers" + errmsg = ( + "LAMMPS.DATAWriter: atom types must be convertible to " + "integers" + ) raise ValueError(errmsg) from None try: @@ -486,18 +502,24 @@ def write(self, selection, frame=None): for btype, attr_name in attrs: features[btype] = atoms.__getattribute__(attr_name) - self.f.write("{:>12d} {}\n".format(len(features[btype]), attr_name)) + self.f.write( + "{:>12d} {}\n".format(len(features[btype]), attr_name) + ) features[btype] = features[btype].atomgroup_intersection( atoms, strict=True ) self.f.write("\n") self.f.write( - "{:>12d} atom types\n".format(max(atoms.types.astype(np.int32))) + "{:>12d} atom types\n".format( + max(atoms.types.astype(np.int32)) + ) ) for btype, attr in features.items(): - self.f.write("{:>12d} {} types\n".format(len(attr.types()), btype)) + self.f.write( + "{:>12d} {} types\n".format(len(attr.types()), btype) + ) self._write_dimensions(atoms.dimensions) @@ -803,7 +825,9 @@ def _read_next_timestep(self): try: # this will automatically select in order of priority # unscaled, scaled, unwrapped, scaled_unwrapped - self.lammps_coordinate_convention = list(convention_to_col_ix)[0] + self.lammps_coordinate_convention = list(convention_to_col_ix)[ + 0 + ] except IndexError: raise ValueError("No coordinate information detected") elif not self.lammps_coordinate_convention in convention_to_col_ix: @@ -831,7 +855,9 @@ def _read_next_timestep(self): "Some of the additional columns are not present " "in the file, they will be ignored" ) - additional_keys = [key for key in self._additional_columns if key in attrs] + additional_keys = [ + key for key in self._additional_columns if key in attrs + ] else: additional_keys = [] for key in additional_keys: @@ -842,7 +868,9 @@ def _read_next_timestep(self): fields = f.readline().split() if ids: indices[i] = fields[attr_to_col_ix["id"]] - coords = np.array([fields[dim] for dim in coord_cols], dtype=np.float32) + coords = np.array( + [fields[dim] for dim in coord_cols], dtype=np.float32 + ) if self._unwrap: images = coords[3:] @@ -859,7 +887,9 @@ def _read_next_timestep(self): # Collect additional cols for attribute_key in additional_keys: - ts.data[attribute_key][i] = fields[attr_to_col_ix[attribute_key]] + ts.data[attribute_key][i] = fields[ + attr_to_col_ix[attribute_key] + ] order = np.argsort(indices) ts.positions = ts.positions[order] @@ -874,7 +904,9 @@ def _read_next_timestep(self): if self.lammps_coordinate_convention.startswith("scaled"): # if coordinates are given in scaled format, undo that - ts.positions = distances.transform_StoR(ts.positions, ts.dimensions) + ts.positions = distances.transform_StoR( + ts.positions, ts.dimensions + ) # Transform to origin after transformation of scaled variables ts.positions -= np.array([xlo, ylo, zlo])[None, :] diff --git a/package/MDAnalysis/coordinates/MMTF.py b/package/MDAnalysis/coordinates/MMTF.py index 94b09fbba1..4e28eed308 100644 --- a/package/MDAnalysis/coordinates/MMTF.py +++ b/package/MDAnalysis/coordinates/MMTF.py @@ -76,7 +76,9 @@ def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): ) warnings.warn(wmsg, DeprecationWarning) - super(MMTFReader, self).__init__(filename, convert_units, n_atoms, **kwargs) + super(MMTFReader, self).__init__( + filename, convert_units, n_atoms, **kwargs + ) @staticmethod def _format_hint(thing): diff --git a/package/MDAnalysis/coordinates/MOL2.py b/package/MDAnalysis/coordinates/MOL2.py index f17c23c70b..104283e897 100644 --- a/package/MDAnalysis/coordinates/MOL2.py +++ b/package/MDAnalysis/coordinates/MOL2.py @@ -145,9 +145,8 @@ class MOL2Reader(base.ReaderBase): .. versionchanged:: 2.2.0 Read MOL2 files with optional columns omitted. """ - - format = "MOL2" - units = {"time": None, "length": "Angstrom"} + format = 'MOL2' + units = {'time': None, 'length': 'Angstrom'} @store_init_arguments def __init__(self, filename, **kwargs): @@ -196,10 +195,8 @@ def parse_block(self, block): atom_lines = sections["atom"] if not len(atom_lines): - raise Exception( - "The mol2 (starting at line {0}) block has no atoms" - "".format(block["start_line"]) - ) + raise Exception("The mol2 (starting at line {0}) block has no atoms" + "".format(block["start_line"])) elif self.n_atoms is None: # First time round, remember the number of atoms self.n_atoms = len(atom_lines) @@ -208,14 +205,13 @@ def parse_block(self, block): "MOL2Reader assumes that the number of atoms remains unchanged" " between frames; the current " "frame has {0}, the next frame has {1} atoms" - "".format(self.n_atoms, len(atom_lines)) - ) + "".format(self.n_atoms, len(atom_lines))) coords = np.zeros((self.n_atoms, 3), dtype=np.float32) for i, a in enumerate(atom_lines): aid, name, x, y, z, atom_type = a.split()[:6] - # x, y, z = float(x), float(y), float(z) + #x, y, z = float(x), float(y), float(z) coords[i, :] = x, y, z return sections, coords @@ -233,12 +229,13 @@ def _read_frame(self, frame): try: block = self.frames[frame] except IndexError: - errmsg = f"Invalid frame {frame} for trajectory with length " f"{len(self)}" + errmsg = (f"Invalid frame {frame} for trajectory with length " + f"{len(self)}") raise IOError(errmsg) from None sections, coords = self.parse_block(block) - for sect in ["molecule", "substructure"]: + for sect in ['molecule', 'substructure']: try: self.ts.data[sect] = sections[sect] except KeyError: @@ -288,10 +285,9 @@ class MOL2Writer(base.WriterBase): Frames now 0-based instead of 1-based """ - - format = "MOL2" + format = 'MOL2' multiframe = True - units = {"time": None, "length": "Angstrom"} + units = {'time': None, 'length': 'Angstrom'} def __init__(self, filename, n_atoms=None, convert_units=True): """Create a new MOL2Writer @@ -308,7 +304,7 @@ def __init__(self, filename, n_atoms=None, convert_units=True): self.frames_written = 0 - self.file = util.anyopen(self.filename, "w") # open file on init + self.file = util.anyopen(self.filename, 'w') # open file on init def close(self): self.file.close() @@ -330,7 +326,7 @@ def encode_block(self, obj): ts = traj.ts try: - molecule = ts.data["molecule"] + molecule = ts.data['molecule'] except KeyError: errmsg = "MOL2Writer cannot currently write non MOL2 data" raise NotImplementedError(errmsg) from None @@ -345,12 +341,11 @@ def encode_block(self, obj): bondgroup = obj.intra_bonds bonds = sorted((b[0], b[1], b.order) for b in bondgroup) bond_lines = ["@BOND"] - bls = [ - "{0:>5} {1:>5} {2:>5} {3:>2}".format( - bid, mapping[atom1], mapping[atom2], order - ) - for bid, (atom1, atom2, order) in enumerate(bonds, start=1) - ] + bls = ["{0:>5} {1:>5} {2:>5} {3:>2}".format(bid, + mapping[atom1], + mapping[atom2], + order) + for bid, (atom1, atom2, order) in enumerate(bonds, start=1)] bond_lines.extend(bls) bond_lines.append("\n") bond_lines = "\n".join(bond_lines) @@ -359,27 +354,23 @@ def encode_block(self, obj): bond_lines = "" atom_lines = ["@ATOM"] - atom_lines.extend( - "{0:>4} {1:>4} {2:>13.4f} {3:>9.4f} {4:>9.4f}" - " {5:>4} {6} {7} {8:>7.4f}" - "".format( - mapping[a], - a.name, - a.position[0], - a.position[1], - a.position[2], - a.type, - a.resid, - a.resname, - a.charge, - ) - for a in obj.atoms - ) + atom_lines.extend("{0:>4} {1:>4} {2:>13.4f} {3:>9.4f} {4:>9.4f}" + " {5:>4} {6} {7} {8:>7.4f}" + "".format(mapping[a], + a.name, + a.position[0], + a.position[1], + a.position[2], + a.type, + a.resid, + a.resname, + a.charge) + for a in obj.atoms) atom_lines.append("\n") atom_lines = "\n".join(atom_lines) try: - substructure = ["@SUBSTRUCTURE\n"] + ts.data["substructure"] + substructure = ["@SUBSTRUCTURE\n"] + ts.data['substructure'] except KeyError: substructure = "" @@ -394,7 +385,8 @@ def encode_block(self, obj): molecule[1] = "{0}\n".format(" ".join(check_sums)) molecule.insert(0, "@MOLECULE\n") - return_val = "".join(molecule) + atom_lines + bond_lines + "".join(substructure) + return_val = ("".join(molecule) + atom_lines + + bond_lines + "".join(substructure)) molecule[0] = molecule_0_store molecule[1] = molecule_1_store diff --git a/package/MDAnalysis/coordinates/NAMDBIN.py b/package/MDAnalysis/coordinates/NAMDBIN.py index 6e24ba39b6..834ea346ae 100644 --- a/package/MDAnalysis/coordinates/NAMDBIN.py +++ b/package/MDAnalysis/coordinates/NAMDBIN.py @@ -66,7 +66,9 @@ def _read_first_frame(self): coord_double = np.fromfile( namdbin, dtype=np.float64, count=self.n_atoms * 3 ) - self.ts._pos[:] = np.array(coord_double, float).reshape(self.n_atoms, 3) + self.ts._pos[:] = np.array(coord_double, float).reshape( + self.n_atoms, 3 + ) @staticmethod def parse_n_atoms(filename, **kwargs): diff --git a/package/MDAnalysis/coordinates/PDB.py b/package/MDAnalysis/coordinates/PDB.py index 4e90016477..5962633976 100644 --- a/package/MDAnalysis/coordinates/PDB.py +++ b/package/MDAnalysis/coordinates/PDB.py @@ -161,7 +161,7 @@ logger = logging.getLogger("MDAnalysis.coordinates.PBD") # Pairs of residue name / atom name in use to deduce PDB formatted atom names -Pair = collections.namedtuple("Atom", "resname name") +Pair = collections.namedtuple('Atom', 'resname name') class PDBReader(base.ReaderBase): @@ -176,7 +176,7 @@ class PDBReader(base.ReaderBase): (:attr:`compound`), *REMARK* (:attr:`remarks`) - all other lines are ignored - + Reads multi-`MODEL`_ PDB files as trajectories. The `Timestep.data` dictionary holds the occupancy and tempfactor (bfactor) values for each atom for a given frame. These attributes are commonly appropriated to store other time varying properties @@ -264,9 +264,8 @@ class PDBReader(base.ReaderBase): Tempfactors (aka bfactors) are now read into the ts.data dictionary each frame. Occupancies are also read into this dictionary. """ - - format = ["PDB", "ENT"] - units = {"time": None, "length": "Angstrom"} + format = ['PDB', 'ENT'] + units = {'time': None, 'length': 'Angstrom'} @store_init_arguments def __init__(self, filename, **kwargs): @@ -281,7 +280,7 @@ def __init__(self, filename, **kwargs): super(PDBReader, self).__init__(filename, **kwargs) try: - self.n_atoms = kwargs["n_atoms"] + self.n_atoms = kwargs['n_atoms'] except KeyError: # hackish, but should work and keeps things DRY # regular MDA usage via Universe doesn't follow this route @@ -310,12 +309,10 @@ def __init__(self, filename, **kwargs): crysts = [] # hack for streamIO - if isinstance(filename, util.NamedStream) and isinstance( - filename.stream, StringIO - ): + if isinstance(filename, util.NamedStream) and isinstance(filename.stream, StringIO): filename.stream = BytesIO(filename.stream.getvalue().encode()) - pdbfile = self._pdbfile = util.anyopen(filename, "rb") + pdbfile = self._pdbfile = util.anyopen(filename, 'rb') line = "magical" while line: @@ -323,21 +320,21 @@ def __init__(self, filename, **kwargs): # (rather than end of current chunk) line = pdbfile.readline() - if line[:5] == b"MODEL": + if line[:5] == b'MODEL': models.append(pdbfile.tell()) - elif line[:5] == b"CRYST": + elif line[:5] == b'CRYST': # remove size of line to get **start** of CRYST line crysts.append(pdbfile.tell() - len(line)) - elif line[:6] == b"HEADER": + elif line[:6] == b'HEADER': # classification = line[10:50] # date = line[50:59] # idCode = line[62:66] header = line[10:66].strip().decode() - elif line[:5] == b"TITLE": + elif line[:5] == b'TITLE': title.append(line[8:80].strip().decode()) - elif line[:6] == b"COMPND": + elif line[:6] == b'COMPND': compound.append(line[7:80].strip().decode()) - elif line[:6] == b"REMARK": + elif line[:6] == b'REMARK': remarks.append(line[6:].strip().decode()) end = pdbfile.tell() # where the file ends @@ -376,14 +373,14 @@ def Writer(self, filename, **kwargs): :class:`PDBWriter` """ - kwargs.setdefault("multiframe", self.n_frames > 1) + kwargs.setdefault('multiframe', self.n_frames > 1) return PDBWriter(filename, **kwargs) def _reopen(self): # Pretend the current TS is -1 (in 0 based) so "next" is the # 0th frame self.close() - self._pdbfile = util.anyopen(self.filename, "rb") + self._pdbfile = util.anyopen(self.filename, 'rb') self.ts.frame = -1 def _read_next_timestep(self, ts=None): @@ -435,7 +432,7 @@ def _read_frame(self, frame): tmp_buf = [] for line in chunk.splitlines(): - if line[:6] in ("ATOM ", "HETATM"): + if line[:6] in ('ATOM ', 'HETATM'): # we only care about coordinates tmp_buf.append([line[30:38], line[38:46], line[46:54]]) try: @@ -451,50 +448,35 @@ def _read_frame(self, frame): else: saw_tempfactor = True pos += 1 - elif line[:6] == "CRYST1": + elif line[:6] == 'CRYST1': # does an implicit str -> float conversion try: - cell_dims = np.array( - [ - line[6:15], - line[15:24], - line[24:33], - line[33:40], - line[40:47], - line[47:54], - ], - dtype=np.float32, - ) + cell_dims = np.array([line[6:15], line[15:24], + line[24:33], line[33:40], + line[40:47], line[47:54]], + dtype=np.float32) except ValueError: - warnings.warn( - "Failed to read CRYST1 record, " - "possibly invalid PDB file, got:\n{}" - "".format(line) - ) + warnings.warn("Failed to read CRYST1 record, " + "possibly invalid PDB file, got:\n{}" + "".format(line)) self.ts.dimensions = None else: - if np.allclose( - cell_dims, np.array([1.0, 1.0, 1.0, 90.0, 90.0, 90.0]) - ): - warnings.warn( - "1 A^3 CRYST1 record," - " this is usually a placeholder." - " Unit cell dimensions will be set to None." - ) + if np.allclose(cell_dims, np.array([1.0, 1.0, 1.0, 90.0, 90.0, 90.0])): + warnings.warn("1 A^3 CRYST1 record," + " this is usually a placeholder." + " Unit cell dimensions will be set to None.") self.ts.dimensions = None else: self.ts.dimensions = cell_dims # check if atom number changed if pos != self.n_atoms: - raise ValueError( - "Inconsistency in file '{}': The number of atoms " - "({}) in trajectory frame {} differs from the " - "number of atoms ({}) in the corresponding " - "topology.\nTrajectories with varying numbers of " - "atoms are currently not supported." - "".format(self.filename, pos, frame, self.n_atoms) - ) + raise ValueError("Inconsistency in file '{}': The number of atoms " + "({}) in trajectory frame {} differs from the " + "number of atoms ({}) in the corresponding " + "topology.\nTrajectories with varying numbers of " + "atoms are currently not supported." + "".format(self.filename, pos, frame, self.n_atoms)) # doing the conversion from list to array at the end is faster self.ts.positions = tmp_buf @@ -505,9 +487,9 @@ def _read_frame(self, frame): if not self.ts.dimensions is None: self.convert_pos_from_native(self.ts.dimensions[:3]) self.ts.frame = frame - self.ts.data["occupancy"] = occupancy + self.ts.data['occupancy'] = occupancy if saw_tempfactor: - self.ts.data["tempfactor"] = tempfactor + self.ts.data['tempfactor'] = tempfactor return self.ts @@ -604,37 +586,32 @@ class PDBWriter(base.WriterBase): Do not write unusable conect records when ag index is larger than 100000. """ - fmt = { - "ATOM": ( + 'ATOM': ( "ATOM {serial:5d} {name:<4s}{altLoc:<1s}{resName:<4s}" "{chainID:1s}{resSeq:4d}{iCode:1s}" " {pos[0]:8.3f}{pos[1]:8.3f}{pos[2]:8.3f}{occupancy:6.2f}" - "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n" - ), - "HETATM": ( + "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n"), + 'HETATM': ( "HETATM{serial:5d} {name:<4s}{altLoc:<1s}{resName:<4s}" "{chainID:1s}{resSeq:4d}{iCode:1s}" " {pos[0]:8.3f}{pos[1]:8.3f}{pos[2]:8.3f}{occupancy:6.2f}" - "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n" - ), - "REMARK": "REMARK {0}\n", - "COMPND": "COMPND {0}\n", - "HEADER": "HEADER {0}\n", - "TITLE": "TITLE {0}\n", - "MODEL": "MODEL {0:>4d}\n", - "NUMMDL": "NUMMDL {0:5d}\n", - "ENDMDL": "ENDMDL\n", - "END": "END\n", - "CRYST1": ( - "CRYST1{box[0]:9.3f}{box[1]:9.3f}{box[2]:9.3f}" - "{ang[0]:7.2f}{ang[1]:7.2f}{ang[2]:7.2f} " - "{spacegroup:<11s}{zvalue:4d}\n" - ), - "CONECT": "CONECT{0}\n", + "{tempFactor:6.2f} {segID:<4s}{element:>2s}{charge:2s}\n"), + 'REMARK': "REMARK {0}\n", + 'COMPND': "COMPND {0}\n", + 'HEADER': "HEADER {0}\n", + 'TITLE': "TITLE {0}\n", + 'MODEL': "MODEL {0:>4d}\n", + 'NUMMDL': "NUMMDL {0:5d}\n", + 'ENDMDL': "ENDMDL\n", + 'END': "END\n", + 'CRYST1': ("CRYST1{box[0]:9.3f}{box[1]:9.3f}{box[2]:9.3f}" + "{ang[0]:7.2f}{ang[1]:7.2f}{ang[2]:7.2f} " + "{spacegroup:<11s}{zvalue:4d}\n"), + 'CONECT': "CONECT{0}\n" } - format = ["PDB", "ENT"] - units = {"time": None, "length": "Angstrom"} + format = ['PDB', 'ENT'] + units = {'time': None, 'length': 'Angstrom'} pdb_coor_limits = {"min": -999.9995, "max": 9999.9995} #: wrap comments into REMARK records that are not longer than # :attr:`remark_max_length` characters. @@ -642,97 +619,36 @@ class PDBWriter(base.WriterBase): multiframe = False # These attributes are used to deduce how to format the atom name. - ions = ( - "FE", - "AS", - "ZN", - "MG", - "MN", - "CO", - "BR", - "CU", - "TA", - "MO", - "AL", - "BE", - "SE", - "PT", - "EU", - "NI", - "IR", - "RH", - "AU", - "GD", - "RU", - ) + ions = ('FE', 'AS', 'ZN', 'MG', 'MN', 'CO', 'BR', + 'CU', 'TA', 'MO', 'AL', 'BE', 'SE', 'PT', + 'EU', 'NI', 'IR', 'RH', 'AU', 'GD', 'RU') # Mercurial can be confused for hydrogen gamma. Yet, mercurial is # rather rare in the PDB. Here are all the residues that contain # mercurial. - special_hg = ("CMH", "EMC", "MBO", "MMC", "HGB", "BE7", "PMB") + special_hg = ('CMH', 'EMC', 'MBO', 'MMC', 'HGB', 'BE7', 'PMB') # Chloride can be confused for a carbon. Here are the residues that # contain chloride. - special_cl = ( - "0QE", - "CPT", - "DCE", - "EAA", - "IMN", - "OCZ", - "OMY", - "OMZ", - "UN9", - "1N1", - "2T8", - "393", - "3MY", - "BMU", - "CLM", - "CP6", - "DB8", - "DIF", - "EFZ", - "LUR", - "RDC", - "UCL", - "XMM", - "HLT", - "IRE", - "LCP", - "PCI", - "VGH", - ) + special_cl = ('0QE', 'CPT', 'DCE', 'EAA', 'IMN', 'OCZ', 'OMY', 'OMZ', + 'UN9', '1N1', '2T8', '393', '3MY', 'BMU', 'CLM', 'CP6', + 'DB8', 'DIF', 'EFZ', 'LUR', 'RDC', 'UCL', 'XMM', 'HLT', + 'IRE', 'LCP', 'PCI', 'VGH') # In these pairs, the atom name is aligned on the first column # (column 13). - include_pairs = (Pair("OEC", "CA1"), Pair("PLL", "PD"), Pair("OEX", "CA1")) + include_pairs = (Pair('OEC', 'CA1'), + Pair('PLL', 'PD'), + Pair('OEX', 'CA1')) # In these pairs, the atom name is aligned on the second column # (column 14), but other rules would align them on the first column. - exclude_pairs = ( - Pair("C14", "C14"), - Pair("C15", "C15"), - Pair("F9F", "F9F"), - Pair("OAN", "OAN"), - Pair("BLM", "NI"), - Pair("BZG", "CO"), - Pair("BZG", "NI"), - Pair("VNL", "CO1"), - Pair("VNL", "CO2"), - Pair("PF5", "FE1"), - Pair("PF5", "FE2"), - Pair("UNL", "UNL"), - ) - - def __init__( - self, - filename, - bonds="conect", - n_atoms=None, - start=0, - step=1, - remarks="Created by PDBWriter", - convert_units=True, - multiframe=None, - reindex=True, - ): + exclude_pairs = (Pair('C14', 'C14'), Pair('C15', 'C15'), + Pair('F9F', 'F9F'), Pair('OAN', 'OAN'), + Pair('BLM', 'NI'), Pair('BZG', 'CO'), + Pair('BZG', 'NI'), Pair('VNL', 'CO1'), + Pair('VNL', 'CO2'), Pair('PF5', 'FE1'), + Pair('PF5', 'FE2'), Pair('UNL', 'UNL')) + + def __init__(self, filename, bonds="conect", n_atoms=None, start=0, step=1, + remarks="Created by PDBWriter", + convert_units=True, multiframe=None, reindex=True): """Create a new PDBWriter Parameters @@ -785,7 +701,7 @@ def __init__( self.step = step self.remarks = remarks - self.pdbfile = util.anyopen(self.filename, "wt") # open file on init + self.pdbfile = util.anyopen(self.filename, 'wt') # open file on init self.has_END = False self.first_frame_done = False @@ -797,28 +713,23 @@ def close(self): .. versionchanged:: 2.0.0 CONECT_ record written just before END_ record """ - if hasattr(self, "pdbfile") and self.pdbfile is not None: + if hasattr(self, 'pdbfile') and self.pdbfile is not None: if not self.has_END: self._write_pdb_bonds() self.END() else: - logger.warning( - "END record has already been written" - " before the final closing of the file" - ) + logger.warning("END record has already been written" + " before the final closing of the file") self.pdbfile.close() self.pdbfile = None def _write_pdb_title(self): if self._multiframe: - self.TITLE( - "MDANALYSIS FRAMES FROM {0:d}, STEP {1:d}: {2!s}" - "".format(self.start, self.step, self.remarks) - ) + self.TITLE("MDANALYSIS FRAMES FROM {0:d}, STEP {1:d}: {2!s}" + "".format(self.start, self.step, self.remarks)) else: - self.TITLE( - "MDANALYSIS FRAME {0:d}: {1!s}" "".format(self.start, self.remarks) - ) + self.TITLE("MDANALYSIS FRAME {0:d}: {1!s}" + "".format(self.start, self.remarks)) def _write_pdb_header(self): """ @@ -875,10 +786,8 @@ def _write_pdb_header(self): self.REMARK("285 CRYST1 RECORD IS INCLUDED, BUT THE VALUES ON") self.REMARK("285 THIS RECORD ARE MEANINGLESS.") - warnings.warn( - "Unit cell dimensions not found. " - "CRYST1 record set to unitary values." - ) + warnings.warn("Unit cell dimensions not found. " + "CRYST1 record set to unitary values.") else: self.CRYST1(self.convert_dimensions_to_unitcell(u.trajectory.ts)) @@ -911,11 +820,9 @@ def _check_pdb_coordinates(self): # such) or add a REMARK (which allows the user to look at the # previously written frames) if self.frames_written > 1: - self.REMARK( - "Incomplete multi-frame trajectory.", - "Coordinates for the current frame cannot be " - "represented in the PDB format.", - ) + self.REMARK("Incomplete multi-frame trajectory.", + "Coordinates for the current frame cannot be " + "represented in the PDB format.") self.close() else: self.close() @@ -932,33 +839,31 @@ def _check_pdb_coordinates(self): else: raise - raise ValueError( - "PDB files must have coordinate values between " - "{0:.3f} and {1:.3f} Angstroem: file writing was " - "aborted.".format(self.pdb_coor_limits["min"], self.pdb_coor_limits["max"]) - ) + raise ValueError("PDB files must have coordinate values between " + "{0:.3f} and {1:.3f} Angstroem: file writing was " + "aborted.".format(self.pdb_coor_limits["min"], + self.pdb_coor_limits["max"])) def _write_pdb_bonds(self): """Writes out all the bond records""" if self.bonds is None: return - if ( - not hasattr(self, "obj") - or not self.obj - or not hasattr(self.obj.universe, "bonds") - ): + if (not hasattr(self, "obj") or + not self.obj or + not hasattr(self.obj.universe, 'bonds')): return bondset = set(itertools.chain(*(a.bonds for a in self.obj.atoms))) if self._reindex: - index_attribute = "index" + index_attribute = 'index' mapping = { - index: i for i, index in enumerate(self.obj.atoms.indices, start=1) + index: i + for i, index in enumerate(self.obj.atoms.indices, start=1) } atoms = np.sort(self.obj.atoms.indices) else: - index_attribute = "id" + index_attribute = 'id' mapping = {id_: id_ for id_ in self.obj.atoms.ids} atoms = np.sort(self.obj.atoms.ids) if self.bonds == "conect": @@ -968,8 +873,7 @@ def _write_pdb_bonds(self): getattr(bond[0], index_attribute), getattr(bond[1], index_attribute), ) - for bond in bondset - if not bond.is_guessed + for bond in bondset if not bond.is_guessed ) elif self.bonds == "all": bonds = ( @@ -987,19 +891,14 @@ def _write_pdb_bonds(self): if not (a1 in mapping and a2 in mapping): continue if mapping[a1] >= 100000 or mapping[a2] >= 100000: - warnings.warn( - "Atom with index >=100000 cannot write " - "bonds to PDB CONECT records." - ) + warnings.warn("Atom with index >=100000 cannot write " + "bonds to PDB CONECT records.") return con[a2].append(a1) con[a1].append(a2) - conect = ( - [mapping[a]] + sorted([mapping[at] for at in con[a]]) - for a in atoms - if a in con - ) + conect = ([mapping[a]] + sorted([mapping[at] for at in con[a]]) + for a in atoms if a in con) for c in conect: self.CONECT(c) @@ -1022,11 +921,9 @@ def _update_frame(self, obj): current frame. """ if isinstance(obj, Timestep): - raise TypeError( - "PDBWriter cannot write Timestep objects " - "directly, since they lack topology information (" - "atom names and types) required in PDB files" - ) + raise TypeError("PDBWriter cannot write Timestep objects " + "directly, since they lack topology information (" + "atom names and types) required in PDB files") if len(obj.atoms) == 0: raise IndexError("Cannot write empty AtomGroup") @@ -1113,7 +1010,7 @@ def write_all_timesteps(self, obj): traj[start] def _write_next_frame(self, ts=None, **kwargs): - """write a new timestep to the PDB file + '''write a new timestep to the PDB file :Keywords: *ts* @@ -1132,12 +1029,13 @@ def _write_next_frame(self, ts=None, **kwargs): .. versionchanged:: 1.0.0 Renamed from `write_next_timestep` to `_write_next_frame`. - """ + ''' if ts is None: try: ts = self.ts except AttributeError: - errmsg = "PBDWriter: no coordinate data to write to " "trajectory file" + errmsg = ("PBDWriter: no coordinate data to write to " + "trajectory file") raise NoDataError(errmsg) from None self._check_pdb_coordinates() self._write_timestep(ts, **kwargs) @@ -1153,22 +1051,21 @@ def _deduce_PDB_atom_name(self, atomname, resname): for more details. """ - if atomname == "": - return "" + if atomname == '': + return '' if len(atomname) >= 4: return atomname[:4] elif len(atomname) == 1: - return " {} ".format(atomname) - elif ( - resname == atomname - or atomname[:2] in self.ions - or atomname == "UNK" - or (resname in self.special_hg and atomname[:2] == "HG") - or (resname in self.special_cl and atomname[:2] == "CL") - or Pair(resname, atomname) in self.include_pairs - ) and Pair(resname, atomname) not in self.exclude_pairs: - return "{:<4}".format(atomname) - return " {:<3}".format(atomname) + return ' {} '.format(atomname) + elif ((resname == atomname + or atomname[:2] in self.ions + or atomname == 'UNK' + or (resname in self.special_hg and atomname[:2] == 'HG') + or (resname in self.special_cl and atomname[:2] == 'CL') + or Pair(resname, atomname) in self.include_pairs) + and Pair(resname, atomname) not in self.exclude_pairs): + return '{:<4}'.format(atomname) + return ' {:<3}'.format(atomname) @staticmethod def _format_PDB_charges(charges: np.ndarray) -> np.ndarray: @@ -1197,7 +1094,7 @@ def _format_PDB_charges(charges: np.ndarray) -> np.ndarray: raise ValueError("formal charges array should be of `int` type") outcharges = charges.astype(object) - outcharges[outcharges == 0] = "" # empty strings for no charge case + outcharges[outcharges == 0] = '' # empty strings for no charge case # using np.where is more efficient than looping in sparse cases for i in np.where(charges < 0)[0]: if charges[i] < -9: @@ -1266,25 +1163,22 @@ def get_attr(attrname, default): return getattr(atoms, attrname) except AttributeError: if self.frames_written == 0: - warnings.warn( - "Found no information for attr: '{}'" - " Using default value of '{}'" - "".format(attrname, default) - ) + warnings.warn("Found no information for attr: '{}'" + " Using default value of '{}'" + "".format(attrname, default)) return np.array([default] * len(atoms)) - - altlocs = get_attr("altLocs", " ") - resnames = get_attr("resnames", "UNK") - icodes = get_attr("icodes", " ") - segids = get_attr("segids", " ") - chainids = get_attr("chainIDs", "") - resids = get_attr("resids", 1) - occupancies = get_attr("occupancies", 1.0) - tempfactors = get_attr("tempfactors", 0.0) - atomnames = get_attr("names", "X") - elements = get_attr("elements", " ") - record_types = get_attr("record_types", "ATOM") - formal_charges = self._format_PDB_charges(get_attr("formalcharges", 0)) + altlocs = get_attr('altLocs', ' ') + resnames = get_attr('resnames', 'UNK') + icodes = get_attr('icodes', ' ') + segids = get_attr('segids', ' ') + chainids = get_attr('chainIDs', '') + resids = get_attr('resids', 1) + occupancies = get_attr('occupancies', 1.0) + tempfactors = get_attr('tempfactors', 0.0) + atomnames = get_attr('names', 'X') + elements = get_attr('elements', ' ') + record_types = get_attr('record_types', 'ATOM') + formal_charges = self._format_PDB_charges(get_attr('formalcharges', 0)) def validate_chainids(chainids, default): """Validate each atom's chainID @@ -1296,7 +1190,7 @@ def validate_chainids(chainids, default): invalid_char_ids = False missing_ids = False - for i, chainid in enumerate(chainids): + for (i, chainid) in enumerate(chainids): if chainid == "": missing_ids = True chainids[i] = default @@ -1308,23 +1202,17 @@ def validate_chainids(chainids, default): chainids[i] = default if invalid_length_ids: - warnings.warn( - "Found chainIDs with invalid length." - " Corresponding atoms will use value of '{}'" - "".format(default) - ) + warnings.warn("Found chainIDs with invalid length." + " Corresponding atoms will use value of '{}'" + "".format(default)) if invalid_char_ids: - warnings.warn( - "Found chainIDs using unnaccepted character." - " Corresponding atoms will use value of '{}'" - "".format(default) - ) + warnings.warn("Found chainIDs using unnaccepted character." + " Corresponding atoms will use value of '{}'" + "".format(default)) if missing_ids: - warnings.warn( - "Found missing chainIDs." - " Corresponding atoms will use value of '{}'" - "".format(default) - ) + warnings.warn("Found missing chainIDs." + " Corresponding atoms will use value of '{}'" + "".format(default)) return chainids chainids = validate_chainids(chainids, "X") @@ -1337,37 +1225,33 @@ def validate_chainids(chainids, default): except AttributeError: raise NoDataError( 'The "id" topology attribute is not set. ' - "Either set the attribute or use reindex=True." + 'Either set the attribute or use reindex=True.' ) else: atom_ids = np.arange(len(atoms)) + 1 for i in range(len(atoms)): vals = {} - vals["serial"] = util.ltruncate_int( - atom_ids[i], 5 - ) # check for overflow here? - vals["name"] = self._deduce_PDB_atom_name(atomnames[i], resnames[i]) - vals["altLoc"] = altlocs[i][:1] - vals["resName"] = resnames[i][:4] - vals["resSeq"] = util.ltruncate_int(resids[i], 4) - vals["iCode"] = icodes[i][:1] - vals["pos"] = pos[i] # don't take off atom so conversion works - vals["occupancy"] = occupancies[i] - vals["tempFactor"] = tempfactors[i] - vals["segID"] = segids[i][:4] - vals["chainID"] = chainids[i] - vals["element"] = elements[i][:2].upper() - vals["charge"] = formal_charges[i] + vals['serial'] = util.ltruncate_int(atom_ids[i], 5) # check for overflow here? + vals['name'] = self._deduce_PDB_atom_name(atomnames[i], resnames[i]) + vals['altLoc'] = altlocs[i][:1] + vals['resName'] = resnames[i][:4] + vals['resSeq'] = util.ltruncate_int(resids[i], 4) + vals['iCode'] = icodes[i][:1] + vals['pos'] = pos[i] # don't take off atom so conversion works + vals['occupancy'] = occupancies[i] + vals['tempFactor'] = tempfactors[i] + vals['segID'] = segids[i][:4] + vals['chainID'] = chainids[i] + vals['element'] = elements[i][:2].upper() + vals['charge'] = formal_charges[i] # record_type attribute, if exists, can be ATOM or HETATM try: self.pdbfile.write(self.fmt[record_types[i]].format(**vals)) except KeyError: - errmsg = ( - f"Found {record_types[i]} for the record type, but " - f"only allowed types are ATOM or HETATM" - ) + errmsg = (f"Found {record_types[i]} for the record type, but " + f"only allowed types are ATOM or HETATM") raise ValueError(errmsg) from None if multiframe: @@ -1381,15 +1265,17 @@ def HEADER(self, trajectory): Strip `trajectory.header` since it can be modified by the user and should be sanitized (Issue #2324) """ - if not hasattr(trajectory, "header"): + if not hasattr(trajectory, 'header'): return header = trajectory.header.strip() - self.pdbfile.write(self.fmt["HEADER"].format(header)) + self.pdbfile.write(self.fmt['HEADER'].format(header)) def TITLE(self, *title): - """Write TITLE_ record.""" + """Write TITLE_ record. + + """ line = " ".join(title) # TODO: should do continuation automatically - self.pdbfile.write(self.fmt["TITLE"].format(line)) + self.pdbfile.write(self.fmt['TITLE'].format(line)) def REMARK(self, *remarks): """Write generic REMARKS_ record (without number). @@ -1399,25 +1285,23 @@ def REMARK(self, *remarks): """ for remark in remarks: - self.pdbfile.write(self.fmt["REMARK"].format(remark)) + self.pdbfile.write(self.fmt['REMARK'].format(remark)) def COMPND(self, trajectory): - if not hasattr(trajectory, "compound"): + if not hasattr(trajectory, 'compound'): return compound = trajectory.compound for c in compound: - self.pdbfile.write(self.fmt["COMPND"].format(c)) - - def CRYST1(self, dimensions, spacegroup="P 1", zvalue=1): - """Write CRYST1_ record.""" - self.pdbfile.write( - self.fmt["CRYST1"].format( - box=dimensions[:3], - ang=dimensions[3:], - spacegroup=spacegroup, - zvalue=zvalue, - ) - ) + self.pdbfile.write(self.fmt['COMPND'].format(c)) + + def CRYST1(self, dimensions, spacegroup='P 1', zvalue=1): + """Write CRYST1_ record. + """ + self.pdbfile.write(self.fmt['CRYST1'].format( + box=dimensions[:3], + ang=dimensions[3:], + spacegroup=spacegroup, + zvalue=zvalue)) def MODEL(self, modelnumber): """Write the MODEL_ record. @@ -1432,7 +1316,7 @@ def MODEL(self, modelnumber): Maximum model number is enforced. """ - self.pdbfile.write(self.fmt["MODEL"].format(int(str(modelnumber)[-4:]))) + self.pdbfile.write(self.fmt['MODEL'].format(int(str(modelnumber)[-4:]))) def END(self): """Write END_ record. @@ -1445,18 +1329,22 @@ def END(self): """ if not self.has_END: # only write a single END record - self.pdbfile.write(self.fmt["END"]) + self.pdbfile.write(self.fmt['END']) self.has_END = True def ENDMDL(self): - """Write the ENDMDL_ record.""" - self.pdbfile.write(self.fmt["ENDMDL"]) + """Write the ENDMDL_ record. + + """ + self.pdbfile.write(self.fmt['ENDMDL']) def CONECT(self, conect): - """Write CONECT_ record.""" + """Write CONECT_ record. + + """ conect = ["{0:5d}".format(entry) for entry in conect] conect = "".join(conect) - self.pdbfile.write(self.fmt["CONECT"].format(conect)) + self.pdbfile.write(self.fmt['CONECT'].format(conect)) class ExtendedPDBReader(PDBReader): @@ -1477,7 +1365,6 @@ class ExtendedPDBReader(PDBReader): .. versionadded:: 0.8 """ - format = "XPDB" @@ -1507,7 +1394,6 @@ class MultiPDBWriter(PDBWriter): .. versionadded:: 0.7.6 """ - - format = ["PDB", "ENT"] + format = ['PDB', 'ENT'] multiframe = True # For Writer registration singleframe = False diff --git a/package/MDAnalysis/coordinates/PDBQT.py b/package/MDAnalysis/coordinates/PDBQT.py index e1e0acc578..5388b1ad9b 100644 --- a/package/MDAnalysis/coordinates/PDBQT.py +++ b/package/MDAnalysis/coordinates/PDBQT.py @@ -157,9 +157,13 @@ def _read_first_frame(self): break if line.startswith("CRYST1"): # lengths - x, y, z = np.float32((line[6:15], line[15:24], line[24:33])) + x, y, z = np.float32( + (line[6:15], line[15:24], line[24:33]) + ) # angles - A, B, G = np.float32((line[33:40], line[40:47], line[47:54])) + A, B, G = np.float32( + (line[33:40], line[40:47], line[47:54]) + ) unitcell[:] = x, y, z, A, B, G if line.startswith(("ATOM", "HETATM")): # convert all entries at the end once for optimal speed @@ -264,7 +268,9 @@ def write(self, selection, frame=None): frame = 0 # should catch cases when we are analyzing a single PDB (?) atoms = selection.atoms # make sure to use atoms (Issue 46) - coor = atoms.positions # can write from selection == Universe (Issue 49) + coor = ( + atoms.positions + ) # can write from selection == Universe (Issue 49) # Check attributes attrs = {} @@ -313,7 +319,9 @@ def write(self, selection, frame=None): raise ValueError( "PDB files must have coordinate values between {0:.3f}" " and {1:.3f} Angstroem: No file was written." - "".format(self.pdb_coor_limits["min"], self.pdb_coor_limits["max"]) + "".format( + self.pdb_coor_limits["min"], self.pdb_coor_limits["max"] + ) ) # Write title record diff --git a/package/MDAnalysis/coordinates/PQR.py b/package/MDAnalysis/coordinates/PQR.py index a3381acc67..a2f5a119f7 100644 --- a/package/MDAnalysis/coordinates/PQR.py +++ b/package/MDAnalysis/coordinates/PQR.py @@ -219,7 +219,9 @@ def __init__(self, filename, convert_units=True, **kwargs): top of the PQR file """ self.filename = util.filename(filename, ext="pqr", keep=True) - self.convert_units = convert_units # convert length and time to base units + self.convert_units = ( + convert_units # convert length and time to base units + ) self.remarks = kwargs.pop("remarks", "PQR file written by MDAnalysis") def write(self, selection, frame=None): @@ -254,7 +256,9 @@ def write(self, selection, frame=None): frame = 0 # should catch cases when we are analyzing a single frame(?) atoms = selection.atoms # make sure to use atoms (Issue 46) - coordinates = atoms.positions # can write from selection == Universe (Issue 49) + coordinates = ( + atoms.positions + ) # can write from selection == Universe (Issue 49) if self.convert_units: self.convert_pos_to_native( coordinates @@ -318,7 +322,9 @@ def write(self, selection, frame=None): pqrfile.write(self.fmt_remark.format(rem, 1)) pqrfile.write( self.fmt_remark.format( - "Input: frame {0} of {1}".format(frame, u.trajectory.filename), + "Input: frame {0} of {1}".format( + frame, u.trajectory.filename + ), 5, ) ) diff --git a/package/MDAnalysis/coordinates/TNG.py b/package/MDAnalysis/coordinates/TNG.py index a5d868360f..44c6890dcf 100644 --- a/package/MDAnalysis/coordinates/TNG.py +++ b/package/MDAnalysis/coordinates/TNG.py @@ -148,7 +148,9 @@ class TNGReader(base.ReaderBase): _forces_blockname, ] - @due.dcite(Doi("10.1002/jcc.23495"), description="The TNG paper", path=__name__) + @due.dcite( + Doi("10.1002/jcc.23495"), description="The TNG paper", path=__name__ + ) @store_init_arguments def __init__(self, filename: str, convert_units: bool = True, **kwargs): """Initialize a TNG trajectory @@ -162,7 +164,9 @@ def __init__(self, filename: str, convert_units: bool = True, **kwargs): """ if not HAS_PYTNG: - raise ImportError("TNGReader: To read TNG files please install pytng") + raise ImportError( + "TNGReader: To read TNG files please install pytng" + ) super(TNGReader, self).__init__(filename, **kwargs) @@ -193,27 +197,35 @@ def __init__(self, filename: str, convert_units: bool = True, **kwargs): self._has_positions = self._positions_blockname in self._block_names if self._has_positions: self._special_block_present[self._positions_blockname] = True - self.ts.positions = self._file_iterator.make_ndarray_for_block_from_name( - self._positions_blockname + self.ts.positions = ( + self._file_iterator.make_ndarray_for_block_from_name( + self._positions_blockname + ) ) self._has_velocities = self._velocities_blockname in self._block_names if self._has_velocities: self._special_block_present[self._velocities_blockname] = True - self.ts.velocities = self._file_iterator.make_ndarray_for_block_from_name( - self._velocities_blockname + self.ts.velocities = ( + self._file_iterator.make_ndarray_for_block_from_name( + self._velocities_blockname + ) ) self._has_forces = self._forces_blockname in self._block_names if self._has_forces: self._special_block_present[self._forces_blockname] = True - self.ts.forces = self._file_iterator.make_ndarray_for_block_from_name( - self._forces_blockname + self.ts.forces = ( + self._file_iterator.make_ndarray_for_block_from_name( + self._forces_blockname + ) ) # check for any additional blocks that will be read into ts.data self._additional_blocks = [ - block for block in self._block_names if block not in self._special_blocks + block + for block in self._block_names + if block not in self._special_blocks ] self._check_strides_and_frames() self._frame = 0 @@ -265,7 +277,9 @@ def _check_strides_and_frames(self): " It will not be read" ) else: - self._additional_blocks_to_read.append(block) # pragma: no cover + self._additional_blocks_to_read.append( + block + ) # pragma: no cover else: self._additional_blocks_to_read.append(block) @@ -289,7 +303,9 @@ def parse_n_atoms(filename: str) -> int: """ if not HAS_PYTNG: - raise ImportError("TNGReader: To read TNG files please install pytng") + raise ImportError( + "TNGReader: To read TNG files please install pytng" + ) with pytng.TNGFileIterator(filename, "r") as tng: n_atoms = tng.n_atoms return n_atoms @@ -471,7 +487,9 @@ def _frame_to_ts( add_block_stride = self._block_strides[block] # check we are on stride for our block if not (add_block_stride % self._global_stride): - block_data = self._file_iterator.make_ndarray_for_block_from_name(block) + block_data = ( + self._file_iterator.make_ndarray_for_block_from_name(block) + ) # additional blocks read into ts.data dictionary ts.data[block] = curr_step.get_blockid( self._block_dictionary[block], block_data diff --git a/package/MDAnalysis/coordinates/TRC.py b/package/MDAnalysis/coordinates/TRC.py index 8e0e755caf..4c7c4009ec 100644 --- a/package/MDAnalysis/coordinates/TRC.py +++ b/package/MDAnalysis/coordinates/TRC.py @@ -229,7 +229,9 @@ def _read_traj_properties(self): # Timestep-block # if "TIMESTEP" == stripped_line: - l_timestep_timevalues.append(float(f.readline().split()[1])) + l_timestep_timevalues.append( + float(f.readline().split()[1]) + ) while stripped_line != "END": stripped_line = f.readline().strip() # @@ -266,7 +268,9 @@ def _read_traj_properties(self): # instead of looping over the file, looking for an END # we can seek to where the end of the block should be. current_pos = f.tell() - len(line) - f.seek(f.tell() - len(line) + block_size["POSITIONRED"]) + f.seek( + f.tell() - len(line) + block_size["POSITIONRED"] + ) # Check if we are at the correct position # If not, set inconsistent_size to true and seek back @@ -279,7 +283,9 @@ def _read_traj_properties(self): f.seek(current_pos) if frame_counter == 0: - errormsg = "No supported blocks were found within the GROMOS trajectory!" + errormsg = ( + "No supported blocks were found within the GROMOS trajectory!" + ) logger.error(errormsg) raise ValueError(errormsg) @@ -288,7 +294,9 @@ def _read_traj_properties(self): traj_properties["l_blockstart_offset"] = l_blockstart_offset if len(l_timestep_timevalues) >= 2: - traj_properties["dt"] = l_timestep_timevalues[1] - l_timestep_timevalues[0] + traj_properties["dt"] = ( + l_timestep_timevalues[1] - l_timestep_timevalues[0] + ) else: traj_properties["dt"] = 0 warnmsg = "The trajectory does not contain TIMESTEP blocks!" @@ -351,7 +359,9 @@ def _read_GROMOS11_trajectory(self): elif ntb_setting in [1, 2]: tmp_a, tmp_b, tmp_c = map(float, f.readline().split()) - tmp_alpha, tmp_beta, tmp_gamma = map(float, f.readline().split()) + tmp_alpha, tmp_beta, tmp_gamma = map( + float, f.readline().split() + ) frameDat["dimensions"] = [ tmp_a, tmp_b, @@ -363,13 +373,21 @@ def _read_GROMOS11_trajectory(self): self.periodic = True # gb_line3 - if sum(abs(float(v)) for v in f.readline().split()) > 1e-10: - errormsg = "This reader doesnt't support a shifted origin!" + if ( + sum(abs(float(v)) for v in f.readline().split()) + > 1e-10 + ): + errormsg = ( + "This reader doesnt't support a shifted origin!" + ) logger.error(errormsg) raise ValueError(errormsg) # gb_line4 - if sum(abs(float(v)) for v in f.readline().split()) > 1e-10: + if ( + sum(abs(float(v)) for v in f.readline().split()) + > 1e-10 + ): errormsg = "This reader doesnt't support yawed, pitched or rolled boxes!" logger.error(errormsg) raise ValueError(errormsg) @@ -381,7 +399,8 @@ def _read_GROMOS11_trajectory(self): break elif any( - non_supp_bn in line for non_supp_bn in TRCReader.NOT_SUPPORTED_BLOCKS + non_supp_bn in line + for non_supp_bn in TRCReader.NOT_SUPPORTED_BLOCKS ): for non_supp_bn in TRCReader.NOT_SUPPORTED_BLOCKS: if non_supp_bn == stripped_line: @@ -396,7 +415,9 @@ def _read_frame(self, i): self._frame = i - 1 # Move position in file just (-2 byte) before the start of the block - self.trcfile.seek(self.traj_properties["l_blockstart_offset"][i] - 2, 0) + self.trcfile.seek( + self.traj_properties["l_blockstart_offset"][i] - 2, 0 + ) return self._read_next_timestep() diff --git a/package/MDAnalysis/coordinates/TRJ.py b/package/MDAnalysis/coordinates/TRJ.py index 60ba641151..e9799e4d94 100644 --- a/package/MDAnalysis/coordinates/TRJ.py +++ b/package/MDAnalysis/coordinates/TRJ.py @@ -141,7 +141,6 @@ from . import base from ..lib import util from ..lib.util import store_init_arguments - logger = logging.getLogger("MDAnalysis.coordinates.AMBER") @@ -173,9 +172,8 @@ class TRJReader(base.ReaderBase): Frames now 0-based instead of 1-based. kwarg `delta` renamed to `dt`, for uniformity with other Readers """ - - format = ["TRJ", "MDCRD", "CRDBOX"] - units = {"time": "ps", "length": "Angstrom"} + format = ['TRJ', 'MDCRD', 'CRDBOX'] + units = {'time': 'ps', 'length': 'Angstrom'} _Timestep = Timestep @store_init_arguments @@ -191,14 +189,14 @@ def __init__(self, filename, n_atoms=None, **kwargs): # FORMAT(10F8.3) (X(i), Y(i), Z(i), i=1,NATOM) self.default_line_parser = util.FORTRANReader("10F8.3") - self.lines_per_frame = int( - np.ceil(3.0 * self.n_atoms / len(self.default_line_parser)) - ) + self.lines_per_frame = int(np.ceil(3.0 * self.n_atoms / len( + self.default_line_parser))) # The last line per frame might have fewer than 10 # We determine right away what parser we need for the last # line because it will be the same for all frames. last_per_line = 3 * self.n_atoms % len(self.default_line_parser) - self.last_line_parser = util.FORTRANReader("{0:d}F8.3".format(last_per_line)) + self.last_line_parser = util.FORTRANReader("{0:d}F8.3".format( + last_per_line)) # FORMAT(10F8.3) BOX(1), BOX(2), BOX(3) # is this always on a separate line?? @@ -243,7 +241,7 @@ def _read_next_timestep(self): if self.periodic: line = next(self.trjfile) box = self.box_line_parser.read(line) - ts.dimensions = box + [90.0, 90.0, 90.0] # assumed + ts.dimensions = box + [90., 90., 90.] # assumed # probably slow ... could be optimized by storing the coordinates in # X,Y,Z lists or directly filling the array; the array/reshape is not @@ -291,7 +289,7 @@ def _detect_amber_box(self): nentries = self.default_line_parser.number_of_matches(line) if nentries == 3: self.periodic = True - ts.dimensions = self.box_line_parser.read(line) + [90.0, 90.0, 90.0] + ts.dimensions = self.box_line_parser.read(line) + [90., 90., 90.] else: self.periodic = False self.close() @@ -342,8 +340,7 @@ def open_trajectory(self): # Chimera uses this check raise OSError( "Header of AMBER formatted trajectory has more than 80 chars. " - "This is probably not a AMBER trajectory." - ) + "This is probably not a AMBER trajectory.") # reset ts ts = self.ts ts.frame = -1 @@ -428,15 +425,13 @@ class NCDFReader(base.ReaderBase): """ - format = ["NCDF", "NC"] + format = ['NCDF', 'NC'] multiframe = True version = "1.0" - units = { - "time": "ps", - "length": "Angstrom", - "velocity": "Angstrom/ps", - "force": "kcal/(mol*Angstrom)", - } + units = {'time': 'ps', + 'length': 'Angstrom', + 'velocity': 'Angstrom/ps', + 'force': 'kcal/(mol*Angstrom)'} _Timestep = Timestep @@ -448,60 +443,55 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): super(NCDFReader, self).__init__(filename, **kwargs) # ensure maskandscale is off so we don't end up double scaling - self.trjfile = NCDFPicklable(self.filename, mmap=self._mmap, maskandscale=False) + self.trjfile = NCDFPicklable(self.filename, + mmap=self._mmap, + maskandscale=False) # AMBER NetCDF files should always have a convention try: conventions = self.trjfile.Conventions - if not ( - "AMBER" in conventions.decode("utf-8").split(",") - or "AMBER" in conventions.decode("utf-8").split() - ): - errmsg = ( - "NCDF trajectory {0} does not conform to AMBER " - "specifications, " - "http://ambermd.org/netcdf/nctraj.xhtml " - "('AMBER' must be one of the token in attribute " - "Conventions)".format(self.filename) - ) + if not ('AMBER' in conventions.decode('utf-8').split(',') or + 'AMBER' in conventions.decode('utf-8').split()): + errmsg = ("NCDF trajectory {0} does not conform to AMBER " + "specifications, " + "http://ambermd.org/netcdf/nctraj.xhtml " + "('AMBER' must be one of the token in attribute " + "Conventions)".format(self.filename)) logger.fatal(errmsg) raise TypeError(errmsg) except AttributeError: - errmsg = "NCDF trajectory {0} is missing Conventions".format(self.filename) + errmsg = "NCDF trajectory {0} is missing Conventions".format( + self.filename) logger.fatal(errmsg) raise ValueError(errmsg) from None # AMBER NetCDF files should also have a ConventionVersion try: - ConventionVersion = self.trjfile.ConventionVersion.decode("utf-8") + ConventionVersion = self.trjfile.ConventionVersion.decode('utf-8') if not ConventionVersion == self.version: - wmsg = ( - "NCDF trajectory format is {0!s} but the reader " - "implements format {1!s}".format(ConventionVersion, self.version) - ) + wmsg = ("NCDF trajectory format is {0!s} but the reader " + "implements format {1!s}".format( + ConventionVersion, self.version)) warnings.warn(wmsg) logger.warning(wmsg) except AttributeError: errmsg = "NCDF trajectory {0} is missing ConventionVersion".format( - self.filename - ) + self.filename) raise ValueError(errmsg) from None # The AMBER NetCDF standard enforces 64 bit offsets if not self.trjfile.version_byte == 2: - errmsg = ( - "NCDF trajectory {0} does not conform to AMBER " - "specifications, as detailed in " - "https://ambermd.org/netcdf/nctraj.xhtml " - "(NetCDF file does not use 64 bit offsets " - "[version_byte = 2])".format(self.filename) - ) + errmsg = ("NCDF trajectory {0} does not conform to AMBER " + "specifications, as detailed in " + "https://ambermd.org/netcdf/nctraj.xhtml " + "(NetCDF file does not use 64 bit offsets " + "[version_byte = 2])".format(self.filename)) logger.fatal(errmsg) raise TypeError(errmsg) # The AMBER NetCDF standard enforces 3D coordinates try: - if not self.trjfile.dimensions["spatial"] == 3: + if not self.trjfile.dimensions['spatial'] == 3: errmsg = "Incorrect spatial value for NCDF trajectory file" raise TypeError(errmsg) except KeyError: @@ -510,46 +500,38 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): # AMBER NetCDF specs require program and programVersion. Warn users # if those attributes do not exist - if not ( - hasattr(self.trjfile, "program") and hasattr(self.trjfile, "programVersion") - ): - wmsg = ( - "NCDF trajectory {0} may not fully adhere to AMBER " - "standards as either the `program` or `programVersion` " - "attributes are missing".format(self.filename) - ) + if not (hasattr(self.trjfile, 'program') and + hasattr(self.trjfile, 'programVersion')): + wmsg = ("NCDF trajectory {0} may not fully adhere to AMBER " + "standards as either the `program` or `programVersion` " + "attributes are missing".format(self.filename)) warnings.warn(wmsg) logger.warning(wmsg) try: - self.n_atoms = self.trjfile.dimensions["atom"] + self.n_atoms = self.trjfile.dimensions['atom'] if n_atoms is not None and n_atoms != self.n_atoms: - errmsg = ( - "Supplied n_atoms ({0}) != natom from ncdf ({1}). " - "Note: n_atoms can be None and then the ncdf value " - "is used!".format(n_atoms, self.n_atoms) - ) + errmsg = ("Supplied n_atoms ({0}) != natom from ncdf ({1}). " + "Note: n_atoms can be None and then the ncdf value " + "is used!".format(n_atoms, self.n_atoms)) raise ValueError(errmsg) except KeyError: - errmsg = "NCDF trajectory {0} does not contain atom " "information".format( - self.filename - ) + errmsg = ("NCDF trajectory {0} does not contain atom " + "information".format(self.filename)) raise ValueError(errmsg) from None try: - self.n_frames = self.trjfile.dimensions["frame"] + self.n_frames = self.trjfile.dimensions['frame'] # example trajectory when read with scipy.io.netcdf has # dimensions['frame'] == None (indicating a record dimension that # can grow) whereas if read with netCDF4 I get # len(dimensions['frame']) == 10: in any case, we need to get # the number of frames from somewhere such as the time variable: if self.n_frames is None: - self.n_frames = self.trjfile.variables["coordinates"].shape[0] + self.n_frames = self.trjfile.variables['coordinates'].shape[0] except KeyError: - errmsg = ( - f"NCDF trajectory {self.filename} does not contain " - f"frame information" - ) + errmsg = (f"NCDF trajectory {self.filename} does not contain " + f"frame information") raise ValueError(errmsg) from None try: @@ -563,91 +545,81 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs): # checks for not-implemented features (other units would need to be # hacked into MDAnalysis.units) try: - self._verify_units(self.trjfile.variables["time"].units, "picosecond") + self._verify_units(self.trjfile.variables['time'].units, 'picosecond') self.has_time = True except KeyError: self.has_time = False - wmsg = ( - "NCDF trajectory does not contain `time` information;" - " `time` will be set as an increasing index" - ) + wmsg = ("NCDF trajectory does not contain `time` information;" + " `time` will be set as an increasing index") warnings.warn(wmsg) logger.warning(wmsg) - self._verify_units(self.trjfile.variables["coordinates"].units, "angstrom") + + self._verify_units(self.trjfile.variables['coordinates'].units, + 'angstrom') # Check for scale_factor attributes for all data variables and # store this to multiply through later (Issue #2323) - self.scale_factors = { - "time": None, - "cell_lengths": None, - "cell_angles": None, - "coordinates": None, - "velocities": None, - "forces": None, - } + self.scale_factors = {'time': None, + 'cell_lengths': None, + 'cell_angles': None, + 'coordinates': None, + 'velocities': None, + 'forces': None} for variable in self.trjfile.variables: - if hasattr(self.trjfile.variables[variable], "scale_factor"): + if hasattr(self.trjfile.variables[variable], 'scale_factor'): if variable in self.scale_factors: scale_factor = self.trjfile.variables[variable].scale_factor if not isinstance(scale_factor, (float, np.floating)): raise TypeError(f"{scale_factor} is not a float") self.scale_factors[variable] = scale_factor else: - errmsg = ( - "scale_factors for variable {0} are " - "not implemented".format(variable) - ) + errmsg = ("scale_factors for variable {0} are " + "not implemented".format(variable)) raise NotImplementedError(errmsg) - self.has_velocities = "velocities" in self.trjfile.variables + self.has_velocities = 'velocities' in self.trjfile.variables if self.has_velocities: - self._verify_units( - self.trjfile.variables["velocities"].units, "angstrom/picosecond" - ) + self._verify_units(self.trjfile.variables['velocities'].units, + 'angstrom/picosecond') - self.has_forces = "forces" in self.trjfile.variables + self.has_forces = 'forces' in self.trjfile.variables if self.has_forces: - self._verify_units( - self.trjfile.variables["forces"].units, "kilocalorie/mole/angstrom" - ) + self._verify_units(self.trjfile.variables['forces'].units, + 'kilocalorie/mole/angstrom') - self.periodic = "cell_lengths" in self.trjfile.variables + self.periodic = 'cell_lengths' in self.trjfile.variables if self.periodic: - self._verify_units(self.trjfile.variables["cell_lengths"].units, "angstrom") + self._verify_units(self.trjfile.variables['cell_lengths'].units, + 'angstrom') # As of v1.0.0 only `degree` is accepted as a unit - cell_angle_units = self.trjfile.variables["cell_angles"].units - self._verify_units(cell_angle_units, "degree") + cell_angle_units = self.trjfile.variables['cell_angles'].units + self._verify_units(cell_angle_units, 'degree') self._current_frame = 0 - self.ts = self._Timestep( - self.n_atoms, - velocities=self.has_velocities, - forces=self.has_forces, - reader=self, # for dt - **self._ts_kwargs, - ) + self.ts = self._Timestep(self.n_atoms, + velocities=self.has_velocities, + forces=self.has_forces, + reader=self, # for dt + **self._ts_kwargs) # load first data frame self._read_frame(0) @staticmethod def _verify_units(eval_unit, expected_units): - if eval_unit.decode("utf-8") != expected_units: - errmsg = ( - "NETCDFReader currently assumes that the trajectory " - "was written in units of {0} instead of {1}".format( - eval_unit.decode("utf-8"), expected_units - ) - ) + if eval_unit.decode('utf-8') != expected_units: + errmsg = ("NETCDFReader currently assumes that the trajectory " + "was written in units of {0} instead of {1}".format( + eval_unit.decode('utf-8'), expected_units)) raise NotImplementedError(errmsg) @staticmethod def parse_n_atoms(filename, **kwargs): with scipy.io.netcdf_file(filename, mmap=None) as f: - n_atoms = f.dimensions["atom"] + n_atoms = f.dimensions['atom'] return n_atoms def _get_var_and_scale(self, variable, frame): @@ -674,27 +646,28 @@ def _read_frame(self, frame): # convention... for netcdf could also be a slice raise TypeError("frame must be a positive integer or zero") if frame >= self.n_frames or frame < 0: - raise IndexError( - "frame index must be 0 <= frame < {0}".format(self.n_frames) - ) + raise IndexError("frame index must be 0 <= frame < {0}".format( + self.n_frames)) # note: self.trjfile.variables['coordinates'].shape == (frames, n_atoms, 3) - ts._pos[:] = self._get_var_and_scale("coordinates", frame) + ts._pos[:] = self._get_var_and_scale('coordinates', frame) if self.has_time: - ts.time = self._get_var_and_scale("time", frame) + ts.time = self._get_var_and_scale('time', frame) if self.has_velocities: - ts._velocities[:] = self._get_var_and_scale("velocities", frame) + ts._velocities[:] = self._get_var_and_scale('velocities', frame) if self.has_forces: - ts._forces[:] = self._get_var_and_scale("forces", frame) + ts._forces[:] = self._get_var_and_scale('forces', frame) if self.periodic: unitcell = np.zeros(6) - unitcell[:3] = self._get_var_and_scale("cell_lengths", frame) - unitcell[3:] = self._get_var_and_scale("cell_angles", frame) + unitcell[:3] = self._get_var_and_scale('cell_lengths', frame) + unitcell[3:] = self._get_var_and_scale('cell_angles', frame) ts.dimensions = unitcell if self.convert_units: self.convert_pos_from_native(ts._pos) # in-place ! - self.convert_time_from_native(ts.time) # in-place ! (hope this works...) + self.convert_time_from_native( + ts.time) # in-place ! (hope this works...) if self.has_velocities: - self.convert_velocities_from_native(ts._velocities, inplace=True) + self.convert_velocities_from_native(ts._velocities, + inplace=True) if self.has_forces: self.convert_forces_from_native(ts._forces, inplace=True) if self.periodic: @@ -721,8 +694,8 @@ def _get_dt(self): AttributeError which triggers the default 1 ps return of dt(). """ try: - t1 = self.trjfile.variables["time"][1] - t0 = self.trjfile.variables["time"][0] + t1 = self.trjfile.variables['time'][1] + t0 = self.trjfile.variables['time'][0] except (IndexError, KeyError): raise AttributeError return t1 - t0 @@ -776,13 +749,13 @@ def Writer(self, filename, **kwargs): ------- :class:`NCDFWriter` """ - n_atoms = kwargs.pop("n_atoms", self.n_atoms) - kwargs.setdefault("remarks", self.remarks) - kwargs.setdefault("convert_units", self.convert_units) - kwargs.setdefault("velocities", self.has_velocities) - kwargs.setdefault("forces", self.has_forces) + n_atoms = kwargs.pop('n_atoms', self.n_atoms) + kwargs.setdefault('remarks', self.remarks) + kwargs.setdefault('convert_units', self.convert_units) + kwargs.setdefault('velocities', self.has_velocities) + kwargs.setdefault('forces', self.has_forces) for key in self.scale_factors: - kwargs.setdefault(f"scale_{key}", self.scale_factors[key]) + kwargs.setdefault(f'scale_{key}', self.scale_factors[key]) return NCDFWriter(filename, n_atoms, **kwargs) @@ -915,32 +888,19 @@ class NCDFWriter(base.WriterBase): """ - format = ["NC", "NCDF"] + format = ['NC', 'NCDF'] multiframe = True version = "1.0" - units = { - "time": "ps", - "length": "Angstrom", - "velocity": "Angstrom/ps", - "force": "kcal/(mol*Angstrom)", - } - - def __init__( - self, - filename, - n_atoms, - remarks=None, - convert_units=True, - velocities=False, - forces=False, - scale_time=None, - scale_cell_lengths=None, - scale_cell_angles=None, - scale_coordinates=None, - scale_velocities=None, - scale_forces=None, - **kwargs, - ): + units = {'time': 'ps', + 'length': 'Angstrom', + 'velocity': 'Angstrom/ps', + 'force': 'kcal/(mol*Angstrom)'} + + def __init__(self, filename, n_atoms, remarks=None, convert_units=True, + velocities=False, forces=False, scale_time=None, + scale_cell_lengths=None, scale_cell_angles=None, + scale_coordinates=None, scale_velocities=None, + scale_forces=None, **kwargs): self.filename = filename if n_atoms == 0: raise ValueError("NCDFWriter: no atoms in output trajectory") @@ -948,9 +908,7 @@ def __init__( # convert length and time to base units on the fly? self.convert_units = convert_units - self.remarks = ( - remarks or "AMBER NetCDF format (MDAnalysis.coordinates.trj.NCDFWriter)" - ) + self.remarks = remarks or "AMBER NetCDF format (MDAnalysis.coordinates.trj.NCDFWriter)" self._first_frame = True # signals to open trajectory self.trjfile = None # open on first write with _init_netcdf() @@ -959,16 +917,16 @@ def __init__( self.has_forces = forces self.scale_factors = { - "time": scale_time, - "cell_lengths": scale_cell_lengths, - "cell_angles": scale_cell_angles, - "coordinates": scale_coordinates, - "velocities": scale_velocities, - "forces": scale_forces, - } + 'time': scale_time, + 'cell_lengths': scale_cell_lengths, + 'cell_angles': scale_cell_angles, + 'coordinates': scale_coordinates, + 'velocities': scale_velocities, + 'forces': scale_forces} # NCDF standard enforces float scale_factors for value in self.scale_factors.values(): - if (value is not None) and (not isinstance(value, (float, np.floating))): + if (value is not None) and ( + not isinstance(value, (float, np.floating))): errmsg = f"scale_factor {value} is not a float" raise TypeError(errmsg) @@ -995,90 +953,89 @@ def _init_netcdf(self, periodic=True): """ if not self._first_frame: raise IOError( - errno.EIO, "Attempt to write to closed file {0}".format(self.filename) - ) + errno.EIO, + "Attempt to write to closed file {0}".format(self.filename)) if netCDF4: - ncfile = netCDF4.Dataset(self.filename, "w", format="NETCDF3_64BIT") + ncfile = netCDF4.Dataset(self.filename, 'w', + format='NETCDF3_64BIT') else: - ncfile = scipy.io.netcdf_file( - self.filename, mode="w", version=2, maskandscale=False - ) - wmsg = ( - "Could not find netCDF4 module. Falling back to MUCH " - "slower scipy.io.netcdf implementation for writing." - ) + ncfile = scipy.io.netcdf_file(self.filename, + mode='w', version=2, + maskandscale=False) + wmsg = ("Could not find netCDF4 module. Falling back to MUCH " + "slower scipy.io.netcdf implementation for writing.") logger.warning(wmsg) warnings.warn(wmsg) # Set global attributes. - setattr(ncfile, "program", "MDAnalysis.coordinates.TRJ.NCDFWriter") - setattr(ncfile, "programVersion", MDAnalysis.__version__) - setattr(ncfile, "Conventions", "AMBER") - setattr(ncfile, "ConventionVersion", "1.0") - setattr(ncfile, "application", "MDAnalysis") + setattr(ncfile, 'program', 'MDAnalysis.coordinates.TRJ.NCDFWriter') + setattr(ncfile, 'programVersion', MDAnalysis.__version__) + setattr(ncfile, 'Conventions', 'AMBER') + setattr(ncfile, 'ConventionVersion', '1.0') + setattr(ncfile, 'application', 'MDAnalysis') # Create dimensions - ncfile.createDimension("frame", None) # unlimited number of steps (can append) - ncfile.createDimension("atom", self.n_atoms) # number of atoms in system - ncfile.createDimension("spatial", 3) # number of spatial dimensions - ncfile.createDimension("cell_spatial", 3) # unitcell lengths - ncfile.createDimension("cell_angular", 3) # unitcell angles - ncfile.createDimension("label", 5) # needed for cell_angular + ncfile.createDimension('frame', + None) # unlimited number of steps (can append) + ncfile.createDimension('atom', + self.n_atoms) # number of atoms in system + ncfile.createDimension('spatial', 3) # number of spatial dimensions + ncfile.createDimension('cell_spatial', 3) # unitcell lengths + ncfile.createDimension('cell_angular', 3) # unitcell angles + ncfile.createDimension('label', 5) # needed for cell_angular # Create variables. - coords = ncfile.createVariable( - "coordinates", "f4", ("frame", "atom", "spatial") - ) - setattr(coords, "units", "angstrom") - if self.scale_factors["coordinates"]: - coords.scale_factor = self.scale_factors["coordinates"] + coords = ncfile.createVariable('coordinates', 'f4', + ('frame', 'atom', 'spatial')) + setattr(coords, 'units', 'angstrom') + if self.scale_factors['coordinates']: + coords.scale_factor = self.scale_factors['coordinates'] - spatial = ncfile.createVariable("spatial", "c", ("spatial",)) - spatial[:] = np.asarray(list("xyz")) + spatial = ncfile.createVariable('spatial', 'c', ('spatial', )) + spatial[:] = np.asarray(list('xyz')) - time = ncfile.createVariable("time", "f4", ("frame",)) - setattr(time, "units", "picosecond") - if self.scale_factors["time"]: - time.scale_factor = self.scale_factors["time"] + time = ncfile.createVariable('time', 'f4', ('frame',)) + setattr(time, 'units', 'picosecond') + if self.scale_factors['time']: + time.scale_factor = self.scale_factors['time'] self.periodic = periodic if self.periodic: - cell_lengths = ncfile.createVariable( - "cell_lengths", "f8", ("frame", "cell_spatial") - ) - setattr(cell_lengths, "units", "angstrom") - if self.scale_factors["cell_lengths"]: - cell_lengths.scale_factor = self.scale_factors["cell_lengths"] - - cell_spatial = ncfile.createVariable("cell_spatial", "c", ("cell_spatial",)) - cell_spatial[:] = np.asarray(list("abc")) - - cell_angles = ncfile.createVariable( - "cell_angles", "f8", ("frame", "cell_angular") - ) - setattr(cell_angles, "units", "degree") - if self.scale_factors["cell_angles"]: - cell_angles.scale_factor = self.scale_factors["cell_angles"] - - cell_angular = ncfile.createVariable( - "cell_angular", "c", ("cell_angular", "label") - ) - cell_angular[:] = np.asarray([list("alpha"), list("beta "), list("gamma")]) + cell_lengths = ncfile.createVariable('cell_lengths', 'f8', + ('frame', 'cell_spatial')) + setattr(cell_lengths, 'units', 'angstrom') + if self.scale_factors['cell_lengths']: + cell_lengths.scale_factor = self.scale_factors['cell_lengths'] + + cell_spatial = ncfile.createVariable('cell_spatial', 'c', + ('cell_spatial', )) + cell_spatial[:] = np.asarray(list('abc')) + + cell_angles = ncfile.createVariable('cell_angles', 'f8', + ('frame', 'cell_angular')) + setattr(cell_angles, 'units', 'degree') + if self.scale_factors['cell_angles']: + cell_angles.scale_factor = self.scale_factors['cell_angles'] + + cell_angular = ncfile.createVariable('cell_angular', 'c', + ('cell_angular', 'label')) + cell_angular[:] = np.asarray([list('alpha'), list('beta '), list( + 'gamma')]) # These properties are optional, and are specified on Writer creation if self.has_velocities: - velocs = ncfile.createVariable( - "velocities", "f4", ("frame", "atom", "spatial") - ) - setattr(velocs, "units", "angstrom/picosecond") - if self.scale_factors["velocities"]: - velocs.scale_factor = self.scale_factors["velocities"] + velocs = ncfile.createVariable('velocities', 'f4', + ('frame', 'atom', 'spatial')) + setattr(velocs, 'units', 'angstrom/picosecond') + if self.scale_factors['velocities']: + velocs.scale_factor = self.scale_factors['velocities'] if self.has_forces: - forces = ncfile.createVariable("forces", "f4", ("frame", "atom", "spatial")) - setattr(forces, "units", "kilocalorie/mole/angstrom") - if self.scale_factors["forces"]: - forces.scale_factor = self.scale_factors["forces"] + forces = ncfile.createVariable('forces', 'f4', + ('frame', 'atom', 'spatial')) + setattr(forces, 'units', 'kilocalorie/mole/angstrom') + if self.scale_factors['forces']: + forces.scale_factor = self.scale_factors['forces'] # Important for netCDF4! Disable maskandscale for created variables! # Won't work if called before variable creation! @@ -1133,8 +1090,7 @@ def _write_next_frame(self, ag): if ts.n_atoms != self.n_atoms: raise IOError( - "NCDFWriter: Timestep does not have the correct number of atoms" - ) + "NCDFWriter: Timestep does not have the correct number of atoms") if self.trjfile is None: # first time step: analyze data and open trajectory accordingly @@ -1191,35 +1147,35 @@ def _write_next_timestep(self, ts): # write step # coordinates - self._set_frame_var_and_scale("coordinates", pos) + self._set_frame_var_and_scale('coordinates', pos) # time - self._set_frame_var_and_scale("time", time) + self._set_frame_var_and_scale('time', time) # unitcell if self.periodic: # cell lengths - self._set_frame_var_and_scale("cell_lengths", unitcell[:3]) + self._set_frame_var_and_scale('cell_lengths', unitcell[:3]) - self._set_frame_var_and_scale("cell_angles", unitcell[3:]) + self._set_frame_var_and_scale('cell_angles', unitcell[3:]) # velocities if self.has_velocities: velocities = ts._velocities if self.convert_units: velocities = self.convert_velocities_to_native( - velocities, inplace=False - ) + velocities, inplace=False) - self._set_frame_var_and_scale("velocities", velocities) + self._set_frame_var_and_scale('velocities', velocities) # forces if self.has_forces: forces = ts._forces if self.convert_units: - forces = self.convert_forces_to_native(forces, inplace=False) + forces = self.convert_forces_to_native( + forces, inplace=False) - self._set_frame_var_and_scale("forces", forces) + self._set_frame_var_and_scale('forces', forces) self.trjfile.sync() self.curr_frame += 1 @@ -1291,9 +1247,10 @@ class NCDFPicklable(scipy.io.netcdf_file): .. _`scipy netcdf API documentation`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.netcdf_file.html """ - def __getstate__(self): - return (self.filename, self.use_mmap, self.version_byte, self.maskandscale) + return (self.filename, self.use_mmap, self.version_byte, + self.maskandscale) def __setstate__(self, args): - self.__init__(args[0], mmap=args[1], version=args[2], maskandscale=args[3]) + self.__init__(args[0], mmap=args[1], version=args[2], + maskandscale=args[3]) diff --git a/package/MDAnalysis/coordinates/TRR.py b/package/MDAnalysis/coordinates/TRR.py index f6581ee597..850825915c 100644 --- a/package/MDAnalysis/coordinates/TRR.py +++ b/package/MDAnalysis/coordinates/TRR.py @@ -57,9 +57,10 @@ class TRRWriter(XDRBaseWriter): """ - format = "TRR" + format = 'TRR' multiframe = True - units = {"time": "ps", "length": "nm", "velocity": "nm/ps", "force": "kJ/(mol*nm)"} + units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps', + 'force': 'kJ/(mol*nm)'} _file = TRRFile def _write_next_frame(self, ag): @@ -116,7 +117,7 @@ def _write_next_frame(self, ag): time = ts.time else: time = self._dt * ts.frame - step = ts.data.get("step", ts.frame) + step = ts.data.get('step', ts.frame) if self._convert_units: dimensions = self.convert_dimensions_to_unitcell(ts, inplace=False) @@ -124,10 +125,11 @@ def _write_next_frame(self, ag): box = triclinic_vectors(dimensions) lmbda = 0 - if "lambda" in ts.data: - lmbda = ts.data["lambda"] + if 'lambda' in ts.data: + lmbda = ts.data['lambda'] - self._xdr.write(xyz, velo, forces, box, step, time, lmbda, self.n_atoms) + self._xdr.write(xyz, velo, forces, box, step, time, lmbda, + self.n_atoms) class TRRReader(XDRBaseReader): @@ -147,22 +149,22 @@ class TRRReader(XDRBaseReader): offsets. """ - - format = "TRR" - units = {"time": "ps", "length": "nm", "velocity": "nm/ps", "force": "kJ/(mol*nm)"} + format = 'TRR' + units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps', + 'force': 'kJ/(mol*nm)'} _writer = TRRWriter _file = TRRFile def _read_next_timestep(self, ts=None): """copy next frame into timestep - + versionadded:: 2.4.0 TRRReader implements this method so that it can use read_direct_xvf to read the data directly into the timestep rather than copying it from a temporary array. """ if self._frame == self.n_frames - 1: - raise IOError(errno.EIO, "trying to go over trajectory limit") + raise IOError(errno.EIO, 'trying to go over trajectory limit') if ts is None: ts = self.ts # allocate arrays to read into, will set to proper values @@ -183,7 +185,7 @@ def _frame_to_ts(self, frame, ts): else: ts.time = self._frame * dt ts.frame = self._frame - ts.data["step"] = frame.step + ts.data['step'] = frame.step ts.has_positions = frame.hasx ts.has_velocities = frame.hasv @@ -218,6 +220,6 @@ def _frame_to_ts(self, frame, ts): if self.convert_units: self.convert_forces_from_native(ts.forces) - ts.data["lambda"] = frame.lmbda + ts.data['lambda'] = frame.lmbda return ts diff --git a/package/MDAnalysis/coordinates/TRZ.py b/package/MDAnalysis/coordinates/TRZ.py index 0bebf57092..82ada24e6a 100644 --- a/package/MDAnalysis/coordinates/TRZ.py +++ b/package/MDAnalysis/coordinates/TRZ.py @@ -93,7 +93,7 @@ class TRZReader(base.ReaderBase): format = "TRZ" - units = {"time": "ps", "length": "nm", "velocity": "nm/ps"} + units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps'} @store_init_arguments def __init__(self, trzfilename, n_atoms=None, **kwargs): @@ -114,93 +114,84 @@ def __init__(self, trzfilename, n_atoms=None, **kwargs): If `n_atoms` or the number of atoms in the topology file do not match the number of atoms in the trajectory. """ - wmsg = ( - "The TRZ reader is deprecated and will be removed in " - "MDAnalysis version 3.0.0" - ) + wmsg = ("The TRZ reader is deprecated and will be removed in " + "MDAnalysis version 3.0.0") warnings.warn(wmsg, DeprecationWarning) - super(TRZReader, self).__init__(trzfilename, **kwargs) + super(TRZReader, self).__init__(trzfilename, **kwargs) if n_atoms is None: - raise ValueError("TRZReader requires the n_atoms keyword") + raise ValueError('TRZReader requires the n_atoms keyword') - self.trzfile = util.anyopen(self.filename, "rb") + self.trzfile = util.anyopen(self.filename, 'rb') self._cache = dict() self._n_atoms = n_atoms self._read_trz_header() - self.ts = Timestep( - self.n_atoms, - velocities=True, - forces=self.has_force, - reader=self, - **self._ts_kwargs - ) + self.ts = Timestep(self.n_atoms, + velocities=True, + forces=self.has_force, + reader=self, + **self._ts_kwargs) # structured dtype of a single trajectory frame - readarg = str(n_atoms) + " angstroms) @@ -255,7 +245,7 @@ def n_atoms(self): return self._n_atoms @property - @cached("n_frames") + @cached('n_frames') def n_frames(self): """Total number of frames in a trajectory""" try: @@ -272,13 +262,9 @@ def _read_trz_n_frames(self, trzfile): fsize = os.fstat(trzfile.fileno()).st_size # size of file in bytes if not (fsize - self._headerdtype.itemsize) % self._dtype.itemsize == 0: - raise IOError( - "Trajectory has incomplete frames" - ) # check that division is sane + raise IOError("Trajectory has incomplete frames") # check that division is sane - nframes = int( - (fsize - self._headerdtype.itemsize) / self._dtype.itemsize - ) # returns long int otherwise + nframes = int((fsize - self._headerdtype.itemsize) / self._dtype.itemsize) # returns long int otherwise return nframes @@ -308,20 +294,20 @@ def _get_dt(self): self._read_frame(curr_frame) @property - @cached("delta") + @cached('delta') def delta(self): """MD integration timestep""" return self.dt / self.skip_timestep @property - @cached("skip_timestep") + @cached('skip_timestep') def skip_timestep(self): """Timesteps between trajectory frames""" curr_frame = self.ts.frame try: - t0 = self.ts.data["frame"] + t0 = self.ts.data['frame'] self.next() - t1 = self.ts.data["frame"] + t1 = self.ts.data['frame'] skip_timestep = t1 - t0 except StopIteration: return 0 @@ -379,13 +365,13 @@ def _reopen(self): def open_trajectory(self): """Open the trajectory file""" if self.trzfile is not None: - raise IOError(errno.EALREADY, "TRZ file already opened", self.filename) + raise IOError(errno.EALREADY, 'TRZ file already opened', self.filename) if not os.path.exists(self.filename): - raise IOError(errno.ENOENT, "TRZ file not found", self.filename) + raise IOError(errno.ENOENT, 'TRZ file not found', self.filename) - self.trzfile = util.anyopen(self.filename, "rb") + self.trzfile = util.anyopen(self.filename, 'rb') - # Reset ts + #Reset ts ts = self.ts ts.frame = -1 @@ -417,12 +403,12 @@ class TRZWriter(base.WriterBase): and will be removed in version 3.0.0. """ - format = "TRZ" + format = 'TRZ' multiframe = True - units = {"time": "ps", "length": "nm", "velocity": "nm/ps"} + units = {'time': 'ps', 'length': 'nm', 'velocity': 'nm/ps'} - def __init__(self, filename, n_atoms, title="TRZ", convert_units=True): + def __init__(self, filename, n_atoms, title='TRZ', convert_units=True): """Create a TRZWriter Parameters @@ -437,10 +423,8 @@ def __init__(self, filename, n_atoms, title="TRZ", convert_units=True): convert_units : bool (optional) units are converted to the MDAnalysis base format; [``True``] """ - wmsg = ( - "The TRZ writer is deprecated and will be removed in " - "MDAnalysis version 3.0.0" - ) + wmsg = ("The TRZ writer is deprecated and will be removed in " + "MDAnalysis version 3.0.0") warnings.warn(wmsg, DeprecationWarning) self.filename = filename @@ -455,71 +439,61 @@ def __init__(self, filename, n_atoms, title="TRZ", convert_units=True): self.convert_units = convert_units - self.trzfile = util.anyopen(self.filename, "wb") + self.trzfile = util.anyopen(self.filename, 'wb') self._writeheader(title) - floatsize = str(n_atoms) + " int: return self.n_frames @@ -704,9 +695,8 @@ def parse_n_atoms(cls, filename, **kwargs): NotImplementedError when the number of atoms can't be deduced """ - raise NotImplementedError( - "{} cannot deduce the number of atoms" "".format(cls.__name__) - ) + raise NotImplementedError("{} cannot deduce the number of atoms" + "".format(cls.__name__)) def next(self) -> Timestep: """Forward one step to next frame.""" @@ -776,8 +766,7 @@ def Writer(self, filename, **kwargs): raise NotImplementedError( "Sorry, there is no Writer for this format in MDAnalysis. " "Please file an enhancement request at " - "https://github.com/MDAnalysis/mdanalysis/issues" - ) + "https://github.com/MDAnalysis/mdanalysis/issues") def OtherWriter(self, filename, **kwargs): """Returns a writer appropriate for *filename*. @@ -791,10 +780,10 @@ def OtherWriter(self, filename, **kwargs): :meth:`Reader.Writer` and :func:`MDAnalysis.Writer` """ - kwargs["n_atoms"] = self.n_atoms # essential - kwargs.setdefault("start", self.frame) + kwargs['n_atoms'] = self.n_atoms # essential + kwargs.setdefault('start', self.frame) try: - kwargs.setdefault("dt", self.dt) + kwargs.setdefault('dt', self.dt) except KeyError: pass return core.writer(filename, **kwargs) @@ -809,7 +798,7 @@ def _read_next_timestep(self, ts=None): ... def __iter__(self): - """Iterate over trajectory frames.""" + """ Iterate over trajectory frames. """ self._reopen() return self @@ -819,16 +808,14 @@ def _reopen(self): Calling next after this should return the first frame """ - pass # pylint: disable=unnecessary-pass + pass # pylint: disable=unnecessary-pass def _apply_limits(self, frame): if frame < 0: frame += len(self) if frame < 0 or frame >= len(self): - raise IndexError( - "Index {} exceeds length of trajectory ({})." - "".format(frame, len(self)) - ) + raise IndexError("Index {} exceeds length of trajectory ({})." + "".format(frame, len(self))) return frame def __getitem__(self, frame): @@ -856,24 +843,19 @@ def __getitem__(self, frame): return FrameIteratorIndices(self, frame) elif isinstance(frame, slice): start, stop, step = self.check_slice_indices( - frame.start, frame.stop, frame.step - ) + frame.start, frame.stop, frame.step) if start == 0 and stop == len(self) and step == 1: return FrameIteratorAll(self) else: return FrameIteratorSliced(self, frame) else: - raise TypeError( - "Trajectories must be an indexed using an integer," - " slice or list of indices" - ) + raise TypeError("Trajectories must be an indexed using an integer," + " slice or list of indices") def _read_frame(self, frame): """Move to *frame* and fill timestep with data.""" - raise TypeError( - "{0} does not support direct frame indexing." - "".format(self.__class__.__name__) - ) + raise TypeError("{0} does not support direct frame indexing." + "".format(self.__class__.__name__)) # Example implementation in the DCDReader: # self._jump_to_frame(frame) # ts = self.ts @@ -959,18 +941,18 @@ def check_slice_indices(self, start, stop, step): """ - slice_dict = {"start": start, "stop": stop, "step": step} + slice_dict = {'start': start, 'stop': stop, 'step': step} for varname, var in slice_dict.items(): if isinstance(var, numbers.Integral): slice_dict[varname] = int(var) - elif var is None: + elif (var is None): pass else: raise TypeError("{0} is not an integer".format(varname)) - start = slice_dict["start"] - stop = slice_dict["stop"] - step = slice_dict["step"] + start = slice_dict['start'] + stop = slice_dict['stop'] + step = slice_dict['step'] if step == 0: raise ValueError("Step size is zero") @@ -999,22 +981,19 @@ def check_slice_indices(self, start, stop, step): return start, stop, step def __repr__(self): - return "<{cls} {fname} with {nframes} frames of {natoms} atoms>" "".format( + return ("<{cls} {fname} with {nframes} frames of {natoms} atoms>" + "".format( cls=self.__class__.__name__, fname=self.filename, nframes=self.n_frames, - natoms=self.n_atoms, - ) - - def timeseries( - self, - asel: Optional["AtomGroup"] = None, - atomgroup: Optional["Atomgroup"] = None, - start: Optional[int] = None, - stop: Optional[int] = None, - step: Optional[int] = None, - order: Optional[str] = "fac", - ) -> np.ndarray: + natoms=self.n_atoms + )) + + def timeseries(self, asel: Optional['AtomGroup']=None, + atomgroup: Optional['Atomgroup']=None, + start: Optional[int]=None, stop: Optional[int]=None, + step: Optional[int]=None, + order: Optional[str]='fac') -> np.ndarray: """Return a subset of coordinate data for an AtomGroup Parameters @@ -1058,8 +1037,7 @@ def timeseries( warnings.warn( "asel argument to timeseries will be renamed to" "'atomgroup' in 3.0, see #3911", - category=DeprecationWarning, - ) + category=DeprecationWarning) if atomgroup: raise ValueError("Cannot provide both asel and atomgroup kwargs") atomgroup = asel @@ -1068,7 +1046,8 @@ def timeseries( if atomgroup is not None: if len(atomgroup) == 0: - raise ValueError("Timeseries requires at least one atom to analyze") + raise ValueError( + "Timeseries requires at least one atom to analyze") atom_numbers = atomgroup.indices natoms = len(atom_numbers) else: @@ -1081,34 +1060,28 @@ def timeseries( coordinates[i, :] = ts.positions[atom_numbers] # switch axes around - default_order = "fac" + default_order = 'fac' if order != default_order: try: newidx = [default_order.index(i) for i in order] except ValueError: - raise ValueError( - f"Unrecognized order key in {order}, " - "must be permutation of 'fac'" - ) + raise ValueError(f"Unrecognized order key in {order}, " + "must be permutation of 'fac'") try: coordinates = np.moveaxis(coordinates, newidx, [0, 1, 2]) except ValueError: - errmsg = ( - "Repeated or missing keys passed to argument " - f"`order`: {order}, each key must be used once" - ) + errmsg = ("Repeated or missing keys passed to argument " + f"`order`: {order}, each key must be used once") raise ValueError(errmsg) return coordinates - # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def add_auxiliary( - self, - aux_spec: Union[str, Dict[str, str]] = None, - auxdata: Union[str, AuxReader] = None, - format: str = None, - **kwargs, - ) -> None: +# TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 + def add_auxiliary(self, + aux_spec: Union[str, Dict[str, str]] = None, + auxdata: Union[str, AuxReader] = None, + format: str = None, + **kwargs) -> None: """Add auxiliary data to be read alongside trajectory. Auxiliary data may be any data timeseries from the trajectory @@ -1171,9 +1144,8 @@ def add_auxiliary( the :ref:`Auxiliary API`. """ if auxdata is None: - raise ValueError( - "No input `auxdata` specified, but it needs " "to be provided." - ) + raise ValueError("No input `auxdata` specified, but it needs " + "to be provided.") if type(auxdata) not in list(_AUXREADERS.values()): # i.e. if auxdata is a file, not an instance of an AuxReader reader_type = get_auxreader_for(auxdata) @@ -1197,11 +1169,11 @@ def remove_auxiliary(self, auxname): @property def aux_list(self): - """Lists the names of added auxiliary data.""" + """ Lists the names of added auxiliary data. """ return self._auxs.keys() def _check_for_aux(self, auxname): - """Check for the existance of an auxiliary *auxname*. If present, + """ Check for the existance of an auxiliary *auxname*. If present, return the AuxReader; if not, raise ValueError """ if auxname in self.aux_list: @@ -1210,7 +1182,7 @@ def _check_for_aux(self, auxname): raise ValueError("No auxiliary named {name}".format(name=auxname)) def next_as_aux(self, auxname): - """Move to the next timestep for which there is at least one step from + """ Move to the next timestep for which there is at least one step from the auxiliary *auxname* within the cutoff specified in *auxname*. This allows progression through the trajectory without encountering @@ -1242,7 +1214,7 @@ def next_as_aux(self, auxname): raise StopIteration # some readers set self._frame to -1, rather than self.frame, on # _reopen; catch here or doesn't read first frame - while self.frame != next_frame or getattr(self, "_frame", 0) == -1: + while self.frame != next_frame or getattr(self, '_frame', 0) == -1: # iterate trajectory until frame is reached ts = self.next() return ts @@ -1265,8 +1237,9 @@ def iter_as_aux(self, auxname): except StopIteration: return - def iter_auxiliary(self, auxname, start=None, stop=None, step=None, selected=None): - """Iterate through the auxiliary *auxname* independently of the trajectory. + def iter_auxiliary(self, auxname, start=None, stop=None, step=None, + selected=None): + """ Iterate through the auxiliary *auxname* independently of the trajectory. Will iterate over the specified steps of the auxiliary (defaults to all steps). Allows to access all values in an auxiliary, including those out @@ -1319,7 +1292,7 @@ def get_aux_attribute(self, auxname, attrname): return getattr(aux, attrname) def set_aux_attribute(self, auxname, attrname, new): - """Set the value of *attrname* in the auxiliary *auxname*. + """ Set the value of *attrname* in the auxiliary *auxname*. Parameters ---------- @@ -1336,13 +1309,13 @@ def set_aux_attribute(self, auxname, attrname, new): :meth:`rename_aux` - to change the *auxname* attribute """ aux = self._check_for_aux(auxname) - if attrname == "auxname": + if attrname == 'auxname': self.rename_aux(auxname, new) else: setattr(aux, attrname, new) def rename_aux(self, auxname, new): - """Change the name of the auxiliary *auxname* to *new*. + """ Change the name of the auxiliary *auxname* to *new*. Provided there is not already an auxiliary named *new*, the auxiliary name will be changed in ts.aux namespace, the trajectory's @@ -1362,9 +1335,8 @@ def rename_aux(self, auxname, new): """ aux = self._check_for_aux(auxname) if new in self.aux_list: - raise ValueError( - "Auxiliary data with name {name} already " "exists".format(name=new) - ) + raise ValueError("Auxiliary data with name {name} already " + "exists".format(name=new)) aux.auxname = new self._auxs[new] = self._auxs.pop(auxname) setattr(self.ts.aux, new, self.ts.aux[auxname]) @@ -1401,7 +1373,7 @@ def get_aux_descriptions(self, auxnames=None): @property def transformations(self): - """Returns the list of transformations""" + """ Returns the list of transformations""" return self._transformations @transformations.setter @@ -1455,19 +1427,18 @@ def add_transformations(self, *transformations): try: self.transformations = transformations except ValueError: - errmsg = ( - "Can't add transformations again. Please create a new " - "Universe object" - ) + errmsg = ("Can't add transformations again. Please create a new " + "Universe object") raise ValueError(errmsg) from None else: self.ts = self._apply_transformations(self.ts) + # call reader here to apply the newly added transformation on the # current loaded frame? def _apply_transformations(self, ts): - """Applies all the transformations given by the user""" + """Applies all the transformations given by the user """ for transform in self.transformations: ts = transform(ts) @@ -1503,7 +1474,6 @@ class ReaderBase(ProtoReader): Removed deprecated flags functionality, use convert_units kwarg instead """ - @store_init_arguments def __init__(self, filename, convert_units=True, **kwargs): super(ReaderBase, self).__init__() @@ -1515,7 +1485,7 @@ def __init__(self, filename, convert_units=True, **kwargs): self.convert_units = convert_units ts_kwargs = {} - for att in ("dt", "time_offset"): + for att in ('dt', 'time_offset'): try: val = kwargs[att] except KeyError: @@ -1568,14 +1538,14 @@ def __init__(cls, name, bases, classdict): try: # grab the string which describes this format # could be either 'PDB' or ['PDB', 'ENT'] for multiple formats - fmt = asiterable(classdict["format"]) + fmt = asiterable(classdict['format']) except KeyError: # not required however pass else: # does the Writer support single and multiframe writing? - single = classdict.get("singleframe", True) - multi = classdict.get("multiframe", False) + single = classdict.get('singleframe', True) + multi = classdict.get('multiframe', False) if single: for f in fmt: @@ -1642,9 +1612,7 @@ def __del__(self): def __repr__(self): try: - return "< {0!s} {1!r} for {2:d} atoms >".format( - self.__class__.__name__, self.filename, self.n_atoms - ) + return "< {0!s} {1!r} for {2:d} atoms >".format(self.__class__.__name__, self.filename, self.n_atoms) except (TypeError, AttributeError): # no trajectory loaded yet or a Writer that does not need e.g. # self.n_atoms @@ -1691,7 +1659,6 @@ class SingleFrameReaderBase(ProtoReader): Fixed a typo in the attribute assignment (`self.atom` → `self.atoms`), which may affect subclasses relying on this value. """ - _err = "{0} only contains a single frame" @store_init_arguments @@ -1705,7 +1672,7 @@ def __init__(self, filename, convert_units=True, n_atoms=None, **kwargs): self.n_atoms = n_atoms ts_kwargs = {} - for att in ("dt", "time_offset"): + for att in ('dt', 'time_offset'): try: val = kwargs[att] except KeyError: @@ -1780,7 +1747,7 @@ def close(self): pass def add_transformations(self, *transformations): - """Add all transformations to be applied to the trajectory. + """ Add all transformations to be applied to the trajectory. This function take as list of transformations as an argument. These transformations are functions that will be called by the Reader and given @@ -1806,17 +1773,17 @@ def add_transformations(self, *transformations): -------- :mod:`MDAnalysis.transformations` """ - # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` - # to avoid unintended behaviour where the coordinates of each frame are transformed - # multiple times when iterating over the trajectory. - # In this method, the trajectory is modified all at once and once only. + #Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` + #to avoid unintended behaviour where the coordinates of each frame are transformed + #multiple times when iterating over the trajectory. + #In this method, the trajectory is modified all at once and once only. super(SingleFrameReaderBase, self).add_transformations(*transformations) for transform in self.transformations: self.ts = transform(self.ts) def _apply_transformations(self, ts): - """Applies the transformations to the timestep.""" + """ Applies the transformations to the timestep.""" # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` # to avoid applying the same transformations multiple times on each frame @@ -1824,17 +1791,16 @@ def _apply_transformations(self, ts): def range_length(start, stop, step): - if step > 0 and start < stop: + if (step > 0 and start < stop): # We go from a lesser number to a larger one. return int(1 + (stop - 1 - start) // step) - elif step < 0 and start > stop: + elif (step < 0 and start > stop): # We count backward from a larger number to a lesser one. return int(1 + (start - 1 - stop) // (-step)) else: # The range is empty. return 0 - # Verbatim copy of code from converters/base.py # Needed to avoid circular imports before removal in # MDAnalysis 3.0.0 @@ -1844,7 +1810,7 @@ class _Convertermeta(type): def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - fmt = asiterable(classdict["lib"]) + fmt = asiterable(classdict['lib']) except KeyError: pass else: @@ -1867,12 +1833,10 @@ class ConverterBase(IOBase, metaclass=_Convertermeta): """ def __init_subclass__(cls): - wmsg = ( - "ConverterBase moved from coordinates.base." - "ConverterBase to converters.base.ConverterBase " - "and will be removed from coordinates.base " - "in MDAnalysis release 3.0.0" - ) + wmsg = ("ConverterBase moved from coordinates.base." + "ConverterBase to converters.base.ConverterBase " + "and will be removed from coordinates.base " + "in MDAnalysis release 3.0.0") warnings.warn(wmsg, DeprecationWarning, stacklevel=2) def __repr__(self): diff --git a/package/MDAnalysis/coordinates/chain.py b/package/MDAnalysis/coordinates/chain.py index 755aa5d0c5..245b760acd 100644 --- a/package/MDAnalysis/coordinates/chain.py +++ b/package/MDAnalysis/coordinates/chain.py @@ -105,40 +105,28 @@ def filter_times(times, dt): """ # Special cases if len(times) == 1: - return [ - 0, - ] + return [0, ] elif len(times) == 2: if times[0][0] < times[1][0]: return [0, 1] elif np.allclose(times[0][0], times[1][0]): - return [ - 1, - ] + return [1, ] else: - return [ - 0, - ] + return [0, ] if np.unique(times).size == 2: - return [ - len(times) - 1, - ] + return [len(times) - 1, ] # more then 2 unique time entries - used_idx = [ - 0, - ] + used_idx = [0, ] - for i, (first, middle, last) in enumerate( - zip(times[:-2], times[1:-1], times[2:]), start=1 - ): + for i, (first, middle, last) in enumerate(zip(times[:-2], times[1:-1], times[2:]), start=1): if np.allclose(first[0], middle[0]): used_idx[-1] = i elif not np.allclose(middle[1] - middle[0], dt): if (middle[0] <= first[1]) and (last[0] <= middle[1]): used_idx.append(i) - elif middle[0] <= first[1]: + elif (middle[0] <= first[1]): used_idx.append(i) # take care of first special case @@ -159,19 +147,15 @@ def check_allowed_filetypes(readers, allowed): allowed : list of allowed formats """ classname = type(readers[0]) - only_one_reader = np.all([isinstance(r, classname) for r in readers]) + only_one_reader = np.all([isinstance(r, classname) for r in readers]) if not only_one_reader: readernames = [type(r) for r in readers] - raise ValueError( - "ChainReader: continuous=true only supported" - " when all files are using the same reader. " - "Found: {}".format(readernames) - ) + raise ValueError("ChainReader: continuous=true only supported" + " when all files are using the same reader. " + "Found: {}".format(readernames)) if readers[0].format not in allowed: - raise NotImplementedError( - "ChainReader: continuous=True only " - "supported for formats: {}".format(allowed) - ) + raise NotImplementedError("ChainReader: continuous=True only " + "supported for formats: {}".format(allowed)) class ChainReader(base.ReaderBase): @@ -231,13 +215,11 @@ class ChainReader(base.ReaderBase): current timestep is retained. """ - - format = "CHAIN" + format = 'CHAIN' @store_init_arguments - def __init__( - self, filenames, skip=1, dt=None, continuous=False, convert_units=True, **kwargs - ): + def __init__(self, filenames, skip=1, dt=None, continuous=False, + convert_units=True, **kwargs): """Set up the chain reader. Parameters @@ -274,19 +256,19 @@ def __init__( unchanged """ - super(ChainReader, self).__init__( - filename="CHAIN", skip=skip, convert_units=convert_units, dt=dt, **kwargs - ) + super(ChainReader, self).__init__(filename='CHAIN', + skip=skip, + convert_units=convert_units, + dt=dt, + **kwargs) filenames = asiterable(filenames) # Override here because single frame readers handle this argument as a # kwarg to a timestep which behaves differently if dt is present or not. if dt is not None: - kwargs["dt"] = dt - self.readers = [ - core.reader(filename, convert_units=convert_units, **kwargs) - for filename in filenames - ] + kwargs['dt'] = dt + self.readers = [core.reader(filename, convert_units=convert_units, **kwargs) + for filename in filenames] # Iterate through all filenames, appending NoneType None for ndarrays self.filenames = [] for fn in filenames: @@ -302,7 +284,7 @@ def __init__( self.__active_reader_index = 0 self.skip = skip - self.n_atoms = self._get_same("n_atoms") + self.n_atoms = self._get_same('n_atoms') # Translation between virtual frames and frames in individual # trajectories. Assumes that individual trajectories i contain frames @@ -315,26 +297,25 @@ def __init__( # trajectory i and local frame f (i.e. readers[i][f] will correspond to # ChainReader[k]). # build map 'start_frames', which is used by _get_local_frame() - n_frames = self._get("n_frames") + n_frames = self._get('n_frames') # [0]: frames are 0-indexed internally # (see Timestep.check_slice_indices()) self._start_frames = np.cumsum([0] + n_frames) self.n_frames = np.sum(n_frames) - self.dts = np.array(self._get("dt")) + self.dts = np.array(self._get('dt')) self.total_times = self.dts * n_frames # calculate new start_frames to have a time continuous trajectory. if continuous: - check_allowed_filetypes(self.readers, ["XTC", "TRR", "LAMMPSDUMP", "TRC"]) + check_allowed_filetypes(self.readers, ['XTC', 'TRR', 'LAMMPSDUMP', + 'TRC']) if np.any(np.array(n_frames) == 1): - raise RuntimeError( - "ChainReader: Need at least two frames in " - "every trajectory with continuous=True" - ) + raise RuntimeError("ChainReader: Need at least two frames in " + "every trajectory with continuous=True") # TODO: allow floating point precision in dt check - dt = self._get_same("dt") - n_frames = np.asarray(self._get("n_frames")) + dt = self._get_same('dt') + n_frames = np.asarray(self._get('n_frames')) self.dts = np.ones(self.dts.shape) * dt # the sorting needs to happen on two levels. The first major level @@ -366,9 +347,7 @@ def __init__( self.total_times = self.dts[used_idx] * n_frames[used_idx] # rebuild lookup table - sf = [ - 0, - ] + sf = [0, ] n_frames = 0 for r1, r2 in zip(self.readers[:-1], self.readers[1:]): r2[0], r1[0] @@ -381,10 +360,8 @@ def __init__( # check for interleaving r1[1] if r1_start_time < start_time < r1.time: - raise RuntimeError( - "ChainReader: Interleaving not supported " - "with continuous=True." - ) + raise RuntimeError("ChainReader: Interleaving not supported " + "with continuous=True.") # find end where trajectory was restarted from for ts in r1[::-1]: @@ -410,11 +387,9 @@ def _format_hint(thing): .. versionadded:: 1.0.0 """ - return ( - not isinstance(thing, np.ndarray) - and util.iterable(thing) - and not util.isstream(thing) - ) + return (not isinstance(thing, np.ndarray) and + util.iterable(thing) and + not util.isstream(thing)) def _get_local_frame(self, k) -> Tuple[int, int]: """Find trajectory index and trajectory frame for chained frame `k`. @@ -460,16 +435,16 @@ def _get_local_frame(self, k) -> Tuple[int, int]: def __getstate__(self): state = self.__dict__.copy() # save ts temporarily otherwise it will be changed during rewinding. - state["ts"] = self.ts.__deepcopy__() + state['ts'] = self.ts.__deepcopy__() # the ts.frame of each reader is set to the chained frame index during # iteration, thus we need to rewind the readers that have been used. # PR #2723 - for reader in state["readers"][: self.__active_reader_index + 1]: + for reader in state['readers'][:self.__active_reader_index + 1]: reader.rewind() # retrieve the current ts - self.ts = state["ts"] + self.ts = state['ts'] return state def __setstate__(self, state): @@ -563,19 +538,15 @@ def _get_same(self, attr): value = values[0] if not np.allclose(values, value): bad_traj = np.array(self.filenames)[values != value] - raise ValueError( - "The following trajectories do not have the correct {0} " - " ({1}):\n{2}".format(attr, value, bad_traj) - ) + raise ValueError("The following trajectories do not have the correct {0} " + " ({1}):\n{2}".format(attr, value, bad_traj)) return value def __activate_reader(self, i): """Make reader `i` the active reader.""" # private method, not to be used by user to avoid a total mess if not (0 <= i < len(self.readers)): - raise IndexError( - "Reader index must be 0 <= i < {0:d}".format(len(self.readers)) - ) + raise IndexError("Reader index must be 0 <= i < {0:d}".format(len(self.readers))) self.__active_reader_index = i self.filename = self.filenames[i] @@ -629,34 +600,24 @@ def _read_next_timestep(self, ts=None): def _reopen(self): """Internal method: Rewind trajectories themselves and trj pointer.""" self.__current_frame = -1 - self._apply("rewind") + self._apply('rewind') def close(self): - self._apply("close") + self._apply('close') def __repr__(self): if len(self.filenames) > 3: - fname = ( - os.path.basename(self.filenames[0]) - if self.filenames[0] - else "numpy.ndarray" - ) + fname = (os.path.basename(self.filenames[0]) + if self.filenames[0] else "numpy.ndarray") fnames = "{fname} and {nfnames} more".format( - fname=fname, nfnames=len(self.filenames) - 1 - ) + fname=fname, + nfnames=len(self.filenames) - 1) else: - fnames = ", ".join( - [ - os.path.basename(fn) if fn else "numpy.ndarray" - for fn in self.filenames - ] - ) - return ( - "<{clsname} containing {fname} with {nframes} frames of {natoms} atoms>" - "".format( - clsname=self.__class__.__name__, - fname=fnames, - nframes=self.n_frames, - natoms=self.n_atoms, - ) - ) + fnames = ", ".join([os.path.basename(fn) if fn else "numpy.ndarray" + for fn in self.filenames]) + return ("<{clsname} containing {fname} with {nframes} frames of {natoms} atoms>" + "".format( + clsname=self.__class__.__name__, + fname=fnames, + nframes=self.n_frames, + natoms=self.n_atoms)) diff --git a/package/MDAnalysis/coordinates/memory.py b/package/MDAnalysis/coordinates/memory.py index 1e0088a718..288ceceac3 100644 --- a/package/MDAnalysis/coordinates/memory.py +++ b/package/MDAnalysis/coordinates/memory.py @@ -249,19 +249,12 @@ class MemoryReader(base.ProtoReader): :meth:`MemoryReader.timeseries` has now been removed. """ - format = "MEMORY" - - def __init__( - self, - coordinate_array, - order="fac", - dimensions=None, - dt=1, - filename=None, - velocities=None, - forces=None, - **kwargs, - ): + format = 'MEMORY' + + def __init__(self, coordinate_array, order='fac', + dimensions=None, dt=1, filename=None, + velocities=None, forces=None, + **kwargs): """ Parameters ---------- @@ -324,31 +317,31 @@ def __init__( if coordinate_array.ndim == 2 and coordinate_array.shape[1] == 3: coordinate_array = coordinate_array[np.newaxis, :, :] except AttributeError: - errmsg = ( - "The input has to be a numpy.ndarray that corresponds " - "to the layout specified by the 'order' keyword." - ) + errmsg = ("The input has to be a numpy.ndarray that corresponds " + "to the layout specified by the 'order' keyword.") raise TypeError(errmsg) from None self.set_array(coordinate_array, order) - self.n_frames = self.coordinate_array.shape[self.stored_order.find("f")] - self.n_atoms = self.coordinate_array.shape[self.stored_order.find("a")] + self.n_frames = \ + self.coordinate_array.shape[self.stored_order.find('f')] + self.n_atoms = \ + self.coordinate_array.shape[self.stored_order.find('a')] if velocities is not None: try: velocities = np.asarray(velocities, dtype=np.float32) except ValueError: - errmsg = f"'velocities' must be array-like got " f"{type(velocities)}" + errmsg = (f"'velocities' must be array-like got " + f"{type(velocities)}") raise TypeError(errmsg) from None # if single frame, make into array of 1 frame if velocities.ndim == 2: velocities = velocities[np.newaxis, :, :] if not velocities.shape == self.coordinate_array.shape: - raise ValueError( - "Velocities has wrong shape {} " - "to match coordinates {}" - "".format(velocities.shape, self.coordinate_array.shape) - ) + raise ValueError('Velocities has wrong shape {} ' + 'to match coordinates {}' + ''.format(velocities.shape, + self.coordinate_array.shape)) self.velocity_array = velocities.astype(np.float32, copy=False) else: self.velocity_array = None @@ -362,17 +355,18 @@ def __init__( if forces.ndim == 2: forces = forces[np.newaxis, :, :] if not forces.shape == self.coordinate_array.shape: - raise ValueError( - "Forces has wrong shape {} " - "to match coordinates {}" - "".format(forces.shape, self.coordinate_array.shape) - ) + raise ValueError('Forces has wrong shape {} ' + 'to match coordinates {}' + ''.format(forces.shape, + self.coordinate_array.shape)) self.force_array = forces.astype(np.float32, copy=False) else: self.force_array = None provided_n_atoms = kwargs.pop("n_atoms", None) - if provided_n_atoms is not None and provided_n_atoms != self.n_atoms: + if (provided_n_atoms is not None and + provided_n_atoms != self.n_atoms + ): raise ValueError( "The provided value for n_atoms ({}) " "does not match the shape of the coordinate " @@ -388,18 +382,17 @@ def __init__( try: dimensions = np.asarray(dimensions, dtype=np.float32) except ValueError: - errmsg = f"'dimensions' must be array-like got " f"{type(dimensions)}" + errmsg = (f"'dimensions' must be array-like got " + f"{type(dimensions)}") raise TypeError(errmsg) from None if dimensions.shape == (6,): # single box, tile this to trajectory length # allows modifying the box of some frames dimensions = np.tile(dimensions, (self.n_frames, 1)) elif dimensions.shape != (self.n_frames, 6): - raise ValueError( - "Provided dimensions array has shape {}. " - "This must be a array of shape (6,) or " - "(n_frames, 6)".format(dimensions.shape) - ) + raise ValueError("Provided dimensions array has shape {}. " + "This must be a array of shape (6,) or " + "(n_frames, 6)".format(dimensions.shape)) self.dimensions_array = dimensions self.ts.frame = -1 @@ -415,7 +408,7 @@ def _format_hint(thing): return isinstance(thing, np.ndarray) @staticmethod - def parse_n_atoms(filename, order="fac", **kwargs): + def parse_n_atoms(filename, order='fac', **kwargs): """Deduce number of atoms in a given array of coordinates Parameters @@ -435,12 +428,14 @@ def parse_n_atoms(filename, order="fac", **kwargs): number of atoms in system """ # assume filename is a numpy array - return filename.shape[order.find("a")] + return filename.shape[order.find('a')] def copy(self): """Return a copy of this Memory Reader""" - vels = self.velocity_array.copy() if self.velocity_array is not None else None - fors = self.force_array.copy() if self.force_array is not None else None + vels = (self.velocity_array.copy() + if self.velocity_array is not None else None) + fors = (self.force_array.copy() + if self.force_array is not None else None) dims = self.dimensions_array.copy() new = self.__class__( @@ -451,7 +446,7 @@ def copy(self): forces=fors, dt=self.ts.dt, filename=self.filename, - **self._kwargs, + **self._kwargs ) new[self.ts.frame] @@ -463,7 +458,7 @@ def copy(self): return new - def set_array(self, coordinate_array, order="fac"): + def set_array(self, coordinate_array, order='fac'): """ Set underlying array in desired column order. @@ -479,7 +474,7 @@ def set_array(self, coordinate_array, order="fac"): coordinates). """ # Only make copy if not already in float32 format - self.coordinate_array = coordinate_array.astype("float32", copy=False) + self.coordinate_array = coordinate_array.astype('float32', copy=False) self.stored_format = order def get_array(self): @@ -493,9 +488,7 @@ def _reopen(self): self.ts.frame = -1 self.ts.time = -1 - def timeseries( - self, asel=None, atomgroup=None, start=0, stop=-1, step=1, order="afc" - ): + def timeseries(self, asel=None, atomgroup=None, start=0, stop=-1, step=1, order='afc'): """Return a subset of coordinate data for an AtomGroup in desired column order. If no selection is given, it will return a view of the underlying array, while a copy is returned otherwise. @@ -520,7 +513,7 @@ def timeseries( .. deprecated:: 2.4.0 Note that `stop` is currently *inclusive* but will be - changed in favour of being *exclusive* in version 3.0. + changed in favour of being *exclusive* in version 3.0. step : int (optional) the number of trajectory frames to skip @@ -542,19 +535,16 @@ def timeseries( warnings.warn( "asel argument to timeseries will be renamed to" "'atomgroup' in 3.0, see #3911", - category=DeprecationWarning, - ) + category=DeprecationWarning) if atomgroup: raise ValueError("Cannot provide both asel and atomgroup kwargs") atomgroup = asel + if stop != -1: - warnings.warn( - "MemoryReader.timeseries inclusive `stop` " - "indexing will be removed in 3.0 in favour of exclusive " - "indexing", - category=DeprecationWarning, - ) + warnings.warn("MemoryReader.timeseries inclusive `stop` " + "indexing will be removed in 3.0 in favour of exclusive " + "indexing", category=DeprecationWarning) array = self.get_array() if order == self.stored_order: @@ -572,41 +562,40 @@ def timeseries( array = np.swapaxes(array, 2, 0) array = np.swapaxes(array, 1, 2) - a_index = order.find("a") - f_index = order.find("f") - stop_index = stop + 1 + a_index = order.find('a') + f_index = order.find('f') + stop_index = stop+1 if stop_index == 0: stop_index = None - basic_slice = ( - [slice(None)] * f_index - + [slice(start, stop_index, step)] - + [slice(None)] * (2 - f_index) - ) + basic_slice = ([slice(None)] * f_index + + [slice(start, stop_index, step)] + + [slice(None)] * (2-f_index)) # Return a view if either: # 1) atomgroup is None # 2) atomgroup corresponds to the selection of all atoms. array = array[tuple(basic_slice)] - if atomgroup is None or atomgroup is atomgroup.universe.atoms: + if (atomgroup is None or atomgroup is atomgroup.universe.atoms): return array else: if len(atomgroup) == 0: - raise ValueError("Timeseries requires at least one atom " "to analyze") + raise ValueError("Timeseries requires at least one atom " + "to analyze") # If selection is specified, return a copy return array.take(asel.indices, a_index) def _read_next_timestep(self, ts=None): """copy next frame into timestep""" - if self.ts.frame >= self.n_frames - 1: - raise IOError(errno.EIO, "trying to go over trajectory limit") + if self.ts.frame >= self.n_frames-1: + raise IOError(errno.EIO, 'trying to go over trajectory limit') if ts is None: ts = self.ts ts.frame += 1 - f_index = self.stored_order.find("f") - basic_slice = ( - [slice(None)] * (f_index) + [self.ts.frame] + [slice(None)] * (2 - f_index) - ) + f_index = self.stored_order.find('f') + basic_slice = ([slice(None)]*(f_index) + + [self.ts.frame] + + [slice(None)]*(2-f_index)) _replace_positions_array(ts, self.coordinate_array[tuple(basic_slice)]) _replace_dimensions(ts, self.dimensions_array[self.ts.frame]) if self.velocity_array is not None: @@ -625,12 +614,15 @@ def _read_frame(self, i): def __repr__(self): """String representation""" - return "<{cls} with {nframes} frames of {natoms} atoms>" "".format( - cls=self.__class__.__name__, nframes=self.n_frames, natoms=self.n_atoms - ) + return ("<{cls} with {nframes} frames of {natoms} atoms>" + "".format( + cls=self.__class__.__name__, + nframes=self.n_frames, + natoms=self.n_atoms + )) def add_transformations(self, *transformations): - """Add all transformations to be applied to the trajectory. + """ Add all transformations to be applied to the trajectory. This function take as list of transformations as an argument. These transformations are functions that will be called by the Reader and given @@ -656,10 +648,10 @@ def add_transformations(self, *transformations): -------- :mod:`MDAnalysis.transformations` """ - # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` - # to avoid unintended behaviour where the coordinates of each frame are transformed - # multiple times when iterating over the trajectory. - # In this method, the trajectory is modified all at once and once only. + #Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` + #to avoid unintended behaviour where the coordinates of each frame are transformed + #multiple times when iterating over the trajectory. + #In this method, the trajectory is modified all at once and once only. super(MemoryReader, self).add_transformations(*transformations) for i, ts in enumerate(self): @@ -667,7 +659,7 @@ def add_transformations(self, *transformations): ts = transform(ts) def _apply_transformations(self, ts): - """Applies the transformations to the timestep.""" + """ Applies the transformations to the timestep.""" # Overrides :meth:`~MDAnalysis.coordinates.base.ProtoReader.add_transformations` # to avoid applying the same transformations multiple times on each frame diff --git a/package/MDAnalysis/core/_get_readers.py b/package/MDAnalysis/core/_get_readers.py index 926c2e37a6..45d61b3cad 100644 --- a/package/MDAnalysis/core/_get_readers.py +++ b/package/MDAnalysis/core/_get_readers.py @@ -192,8 +192,12 @@ def get_writer_for(filename, format=None, multiframe=None): format = format.upper() if multiframe is None: # Multiframe takes priority, else use singleframe - options = copy.copy(_SINGLEFRAME_WRITERS) # do copy to avoid changing in place - options.update(_MULTIFRAME_WRITERS) # update overwrites existing entries + options = copy.copy( + _SINGLEFRAME_WRITERS + ) # do copy to avoid changing in place + options.update( + _MULTIFRAME_WRITERS + ) # update overwrites existing entries errmsg = "No trajectory or frame writer for format '{0}'" elif multiframe is True: options = _MULTIFRAME_WRITERS diff --git a/package/MDAnalysis/core/groups.py b/package/MDAnalysis/core/groups.py index 54e5a9a886..40044be7c8 100644 --- a/package/MDAnalysis/core/groups.py +++ b/package/MDAnalysis/core/groups.py @@ -160,7 +160,9 @@ def make_classes(): for cls in groups: bases[cls] = GBase._subclass(is_group=True) # CBase for patching all components - CBase = bases[ComponentBase] = _TopologyAttrContainer._subclass(is_group=False) + CBase = bases[ComponentBase] = _TopologyAttrContainer._subclass( + is_group=False + ) for cls in components: bases[cls] = CBase._subclass(is_group=False) @@ -418,9 +420,14 @@ def __getattr__(self, attr): ) # missing required topologyattr else: - err = "{selfcls}.{attrname} not available; " "this requires {topattr}" + err = ( + "{selfcls}.{attrname} not available; " + "this requires {topattr}" + ) raise NoDataError( - err.format(selfcls=selfcls, attrname=attrname, topattr=topattr) + err.format( + selfcls=selfcls, attrname=attrname, topattr=topattr + ) ) else: @@ -527,7 +534,9 @@ def wrapped(self, other): "".format(function.__name__) ) if self.universe is not other.universe: - raise ValueError("Can't operate on objects from different Universes") + raise ValueError( + "Can't operate on objects from different Universes" + ) return function(self, other) return wrapped @@ -664,7 +673,10 @@ def __getattr__(self, attr): if attr in _TOPOLOGY_ATTRS: cls = _TOPOLOGY_ATTRS[attr] if attr == cls.singular and attr != cls.attrname: - err = "{selfcls} has no attribute {attr}. " "Do you mean {plural}?" + err = ( + "{selfcls} has no attribute {attr}. " + "Do you mean {plural}?" + ) raise AttributeError( err.format(selfcls=selfcls, attr=attr, plural=cls.attrname) ) @@ -728,7 +740,9 @@ def __radd__(self, other): else: raise TypeError( "unsupported operand type(s) for +:" - " '{}' and '{}'".format(type(self).__name__, type(other).__name__) + " '{}' and '{}'".format( + type(self).__name__, type(other).__name__ + ) ) def __sub__(self, other): @@ -881,7 +895,9 @@ def _asunique(self, group, sorted=False, set_mask=False): if sorted: if set_mask: - unique_ix, restore_mask = np.unique(self.ix, return_inverse=True) + unique_ix, restore_mask = np.unique( + self.ix, return_inverse=True + ) self._unique_restore_mask = restore_mask else: unique_ix = unique_int_1d(self.ix) @@ -1157,7 +1173,9 @@ def center(self, weights, wrap=False, unwrap=False, compound="group"): if wrap: coords = atoms.pack_into_box(inplace=False) elif unwrap: - coords = atoms.unwrap(compound=comp, reference=None, inplace=False) + coords = atoms.unwrap( + compound=comp, reference=None, inplace=False + ) else: coords = atoms.positions # If there's no atom, return its (empty) coordinates unchanged. @@ -1169,14 +1187,16 @@ def center(self, weights, wrap=False, unwrap=False, compound="group"): return coords.mean(axis=0) # promote weights to dtype if required: weights = weights.astype(dtype, copy=False) - return np.einsum("ij,ij->j", coords, weights[:, None]) / weights.sum() + return ( + np.einsum("ij,ij->j", coords, weights[:, None]) / weights.sum() + ) # When compound split caching gets implemented it will be clever to # preempt at this point whether or not stable sorting will be needed # later for unwrap (so that we don't split now with non-stable sort, # only to have to re-split with stable sort if unwrap is requested). - (atom_masks, compound_masks, n_compounds) = self._split_by_compound_indices( - comp + (atom_masks, compound_masks, n_compounds) = ( + self._split_by_compound_indices(comp) ) # Unwrap Atoms @@ -1198,7 +1218,9 @@ def center(self, weights, wrap=False, unwrap=False, compound="group"): _centers = _coords.mean(axis=1) else: _weights = weights[atom_mask] - _centers = np.einsum("ijk,ijk->ik", _coords, _weights[:, :, None]) + _centers = np.einsum( + "ijk,ijk->ik", _coords, _weights[:, :, None] + ) _centers /= _weights.sum(axis=1)[:, None] centers[compound_mask] = _centers if wrap: @@ -1384,8 +1406,8 @@ def accumulate(self, attribute, function=np.sum, compound="group"): if comp == "group": return function(attribute_values, axis=0) - (atom_masks, compound_masks, n_compounds) = self._split_by_compound_indices( - comp + (atom_masks, compound_masks, n_compounds) = ( + self._split_by_compound_indices(comp) ) higher_dims = list(attribute_values.shape[1:]) @@ -1988,7 +2010,8 @@ def unwrap(self, compound="fragments", reference="com", inplace=True): # ResidueGroups or SegmentGroups if reference == "com" and not hasattr(unique_atoms, "masses"): raise NoDataError( - "Cannot perform unwrap with reference='com', " "this requires masses." + "Cannot perform unwrap with reference='com', " + "this requires masses." ) # Sanity checking of the compound parameter is done downstream in @@ -2056,7 +2079,9 @@ def unwrap(self, compound="fragments", reference="com", inplace=True): refpos = positions[atom_mask].mean(axis=1) refpos = refpos.astype(np.float32, copy=False) target = distances.apply_PBC(refpos, self.dimensions) - positions[atom_mask] += target[:, None, :] - refpos[:, None, :] + positions[atom_mask] += ( + target[:, None, :] - refpos[:, None, :] + ) if inplace: unique_atoms.positions = positions if not atoms.isunique: @@ -2216,7 +2241,9 @@ def concatenate(self, other): .. versionadded:: 0.16.0 """ o_ix = other.ix_array - return self._derived_class(np.concatenate([self.ix, o_ix]), self.universe) + return self._derived_class( + np.concatenate([self.ix, o_ix]), self.universe + ) @_only_same_level def union(self, other): @@ -2303,7 +2330,9 @@ def intersection(self, other): .. versionadded:: 0.16 """ o_ix = other.ix_array - return self._derived_class(np.intersect1d(self.ix, o_ix), self.universe) + return self._derived_class( + np.intersect1d(self.ix, o_ix), self.universe + ) @_only_same_level def subtract(self, other): @@ -2807,7 +2836,9 @@ def residues(self, new): errmsg = ( "Can only set AtomGroup residues to Residue " "or ResidueGroup not {}".format( - ", ".join(type(r) for r in new if not isinstance(r, Residue)) + ", ".join( + type(r) for r in new if not isinstance(r, Residue) + ) ) ) raise TypeError(errmsg) from None @@ -2849,7 +2880,8 @@ def segments(self): @segments.setter def segments(self, new): raise NotImplementedError( - "Cannot assign Segments to AtomGroup. " "Segments are assigned to Residues" + "Cannot assign Segments to AtomGroup. " + "Segments are assigned to Residues" ) @property @@ -2978,7 +3010,9 @@ def asunique(self, sorted=False): .. versionadded:: 2.0.0 """ - return self._asunique(sorted=sorted, group=self.universe.atoms, set_mask=True) + return self._asunique( + sorted=sorted, group=self.universe.atoms, set_mask=True + ) @property def positions(self): @@ -3578,7 +3612,10 @@ def split(self, level): ) raise ValueError(errmsg) from None - return [self[levelindices == index] for index in unique_int_1d(levelindices)] + return [ + self[levelindices == index] + for index in unique_int_1d(levelindices) + ] def guess_bonds(self, vdwradii=None, fudge_factor=0.55, lower_bound=0.1): """Guess bonds, angles, and dihedrals between the atoms in this @@ -3659,7 +3696,9 @@ def bond(self): .. versionadded:: 0.11.0 """ if len(self) != 2: - raise ValueError("bond only makes sense for a group with exactly 2 atoms") + raise ValueError( + "bond only makes sense for a group with exactly 2 atoms" + ) return topologyobjects.Bond(self.ix, self.universe) @property @@ -3676,7 +3715,9 @@ def angle(self): .. versionadded:: 0.11.0 """ if len(self) != 3: - raise ValueError("angle only makes sense for a group with exactly 3 atoms") + raise ValueError( + "angle only makes sense for a group with exactly 3 atoms" + ) return topologyobjects.Angle(self.ix, self.universe) @property @@ -3750,7 +3791,9 @@ def cmap(self): .. versionadded:: 1.0.0 """ if len(self) != 5: - raise ValueError("cmap only makes sense for a group with exactly 5 atoms") + raise ValueError( + "cmap only makes sense for a group with exactly 5 atoms" + ) return topologyobjects.CMap(self.ix, self.universe) convert_to = Accessor("convert_to", ConverterWrapper) @@ -3871,7 +3914,9 @@ def write( # Try and select a Class using get_ methods (becomes `writer`) # Once (and if!) class is selected, use it in with block try: - writer = get_writer_for(filename, format=file_format, multiframe=multiframe) + writer = get_writer_for( + filename, format=file_format, multiframe=multiframe + ) except (ValueError, TypeError): pass else: @@ -4084,7 +4129,9 @@ def segments(self, new): errmsg = ( "Can only set ResidueGroup segments to Segment " "or SegmentGroup, not {}".format( - ", ".join(type(r) for r in new if not isinstance(r, Segment)) + ", ".join( + type(r) for r in new if not isinstance(r, Segment) + ) ) ) raise TypeError(errmsg) from None @@ -4403,7 +4450,9 @@ class ComponentBase(_MutableBase): def __init__(self, ix, u): # index of component if not isinstance(ix, numbers.Integral): - raise IndexError("Component can only be indexed by a single integer") + raise IndexError( + "Component can only be indexed by a single integer" + ) self._ix = ix self._u = u @@ -4413,9 +4462,14 @@ def __getattr__(self, attr): if attr in _TOPOLOGY_ATTRS: cls = _TOPOLOGY_ATTRS[attr] if attr == cls.attrname and attr != cls.singular: - err = "{selfcls} has no attribute {attr}. " "Do you mean {singular}?" + err = ( + "{selfcls} has no attribute {attr}. " + "Do you mean {singular}?" + ) raise AttributeError( - err.format(selfcls=selfcls, attr=attr, singular=cls.singular) + err.format( + selfcls=selfcls, attr=attr, singular=cls.singular + ) ) else: err = "This Universe does not contain {singular} information" @@ -4456,7 +4510,9 @@ def __add__(self, other): """ o_ix = other.ix_array - return self.level.plural(np.concatenate([self.ix_array, o_ix]), self.universe) + return self.level.plural( + np.concatenate([self.ix_array, o_ix]), self.universe + ) def __radd__(self, other): """Using built-in sum requires supporting 0 + self. If other is @@ -4477,7 +4533,9 @@ def __radd__(self, other): else: raise TypeError( "unsupported operand type(s) for +:" - " '{}' and '{}'".format(type(self).__name__, type(other).__name__) + " '{}' and '{}'".format( + type(self).__name__, type(other).__name__ + ) ) @property @@ -4554,7 +4612,8 @@ def residue(self): def residue(self, new): if not isinstance(new, Residue): raise TypeError( - "Can only set Atom residue to Residue, not {}" "".format(type(new)) + "Can only set Atom residue to Residue, not {}" + "".format(type(new)) ) self.universe._topology.tt.move_atom(self.ix, new.resindex) @@ -4685,7 +4744,8 @@ def segment(self): def segment(self, new): if not isinstance(new, Segment): raise TypeError( - "Can only set Residue segment to Segment, not {}" "".format(type(new)) + "Can only set Residue segment to Segment, not {}" + "".format(type(new)) ) self.universe._topology.tt.move_residue(self.ix, new.segindex) @@ -4734,7 +4794,9 @@ def residues(self): """A :class:`ResidueGroup` of :class:`Residues` present in this :class:`Segment`. """ - rg = self.universe.residues[self.universe._topology.resindices[self][0]] + rg = self.universe.residues[ + self.universe._topology.resindices[self][0] + ] rg._cache["isunique"] = True rg._cache["issorted"] = True rg._cache["sorted_unique"] = rg diff --git a/package/MDAnalysis/core/selection.py b/package/MDAnalysis/core/selection.py index 01dbb79bf0..d47f4d7ac1 100644 --- a/package/MDAnalysis/core/selection.py +++ b/package/MDAnalysis/core/selection.py @@ -64,7 +64,6 @@ #: Delimiters include ":", "-", "to" and can have arbitrary whitespace. RANGE_PATTERN = r"\s*(?:[:-]| to )\s*" - def is_keyword(val): """Is val a selection keyword? @@ -74,9 +73,10 @@ def is_keyword(val): - (Parentheses) - The value `None` (used as EOF in selection strings) """ - return ( - val in _SELECTIONDICT or val in _OPERATIONS or val in ["(", ")"] or val is None - ) + return (val in _SELECTIONDICT or + val in _OPERATIONS or + val in ['(', ')'] or + val is None) def grab_not_keywords(tokens): @@ -145,22 +145,18 @@ def join_separated_values(values): except IndexError: given = f"{' '.join(_values)} {v} {' '.join(values)}" raise SelectionError(f"Invalid expression given: {given}") - elif _values and ( - v[:2] in ("--", "to") - or v[0] == ":" - or any(_values[-1].endswith(x) for x in DELIMITERS) - ): + elif _values and (v[:2] in ('--', 'to') or v[0] == ":" or + any(_values[-1].endswith(x) for x in DELIMITERS)): _values[-1] = f"{_values[-1]} {v}" else: _values.append(v) return _values - _SELECTIONDICT = {} _OPERATIONS = {} # These are named args to select_atoms that have a special meaning and must # not be allowed as names for the 'group' keyword. -_RESERVED_KWARGS = ("updating",) +_RESERVED_KWARGS=('updating',) # And and Or are exception and aren't strictly a Selection @@ -170,7 +166,7 @@ class _Operationmeta(type): def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - _OPERATIONS[classdict["token"]] = cls + _OPERATIONS[classdict['token']] = cls except KeyError: pass @@ -186,7 +182,7 @@ def apply(self, *args, **kwargs): class AndOperation(LogicOperation): - token = "and" + token = 'and' precedence = 3 def _apply(self, group): @@ -200,7 +196,7 @@ def _apply(self, group): class OrOperation(LogicOperation): - token = "or" + token = 'or' precedence = 3 def _apply(self, group): @@ -213,19 +209,16 @@ def _apply(self, group): return group.universe.atoms[idx] - def return_empty_on_apply(func): """ Decorator to return empty AtomGroups from the apply() function without evaluating it """ - @functools.wraps(func) def _apply(self, group): if len(group) == 0: return group return func(self, group) - return _apply @@ -233,8 +226,8 @@ class _Selectionmeta(type): def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - _SELECTIONDICT[classdict["token"]] = cls - _SELECTIONDICT[classdict["token"].lower()] = cls + _SELECTIONDICT[classdict['token']] = cls + _SELECTIONDICT[classdict['token'].lower()] = cls except KeyError: pass @@ -249,7 +242,7 @@ def apply(self, *args, **kwargs): class AllSelection(Selection): - token = "all" + token = 'all' def _apply(self, group): # Check whether group is identical to the one stored @@ -269,7 +262,7 @@ def __init__(self, parser, tokens): class NotSelection(UnarySelection): - token = "not" + token = 'not' precedence = 5 def _apply(self, group): @@ -278,7 +271,7 @@ def _apply(self, group): class GlobalSelection(UnarySelection): - token = "global" + token = 'global' precedence = 5 def _apply(self, group): @@ -293,7 +286,7 @@ class ByResSelection(UnarySelection): Use :code:`"resindices"` instead of :code:`"resids"` (see #2669 and #2672) """ - token = "byres" + token = 'byres' precedence = 1 def _apply(self, group): @@ -305,7 +298,7 @@ def _apply(self, group): class AroundSelection(Selection): - token = "around" + token = 'around' precedence = 1 def __init__(self, parser, tokens): @@ -325,17 +318,16 @@ def _apply(self, group): return sys[[]] box = group.dimensions if self.periodic else None - pairs = distances.capped_distance( - sel.positions, sys.positions, self.cutoff, box=box, return_distances=False - ) + pairs = distances.capped_distance(sel.positions, sys.positions, + self.cutoff, box=box, + return_distances=False) if pairs.size > 0: indices = np.sort(pairs[:, 1]) return sys[np.asarray(indices, dtype=np.int64)] - class SphericalLayerSelection(Selection): - token = "sphlayer" + token = 'sphlayer' precedence = 1 def __init__(self, parser, tokens): @@ -354,14 +346,10 @@ def _apply(self, group): box = group.dimensions if self.periodic else None ref = sel.center_of_geometry().reshape(1, 3).astype(np.float32) - pairs = distances.capped_distance( - ref, - group.positions, - self.exRadius, - min_cutoff=self.inRadius, - box=box, - return_distances=False, - ) + pairs = distances.capped_distance(ref, group.positions, self.exRadius, + min_cutoff=self.inRadius, + box=box, + return_distances=False) if pairs.size > 0: indices = np.sort(pairs[:, 1]) @@ -369,7 +357,7 @@ def _apply(self, group): class IsoLayerSelection(Selection): - token = "isolayer" + token = 'isolayer' precedence = 1 def __init__(self, parser, tokens): @@ -390,17 +378,17 @@ def _apply(self, group): return sys[[]] box = group.dimensions if self.periodic else None - pairs_outer = distances.capped_distance( - sel.positions, sys.positions, self.exRadius, box=box, return_distances=False - ) - pairs_inner = distances.capped_distance( - sel.positions, sys.positions, self.inRadius, box=box, return_distances=False - ) + pairs_outer = distances.capped_distance(sel.positions, sys.positions, + self.exRadius, box=box, + return_distances=False) + pairs_inner = distances.capped_distance(sel.positions, sys.positions, + self.inRadius, box=box, + return_distances=False) if pairs_outer.size > 0: - sys_ind_outer = np.sort(np.unique(pairs_outer[:, 1])) + sys_ind_outer = np.sort(np.unique(pairs_outer[:,1])) if pairs_inner.size > 0: - sys_ind_inner = np.sort(np.unique(pairs_inner[:, 1])) + sys_ind_inner = np.sort(np.unique(pairs_inner[:,1])) indices = sys_ind_outer[~np.isin(sys_ind_outer, sys_ind_inner)] else: indices = sys_ind_outer @@ -409,7 +397,7 @@ def _apply(self, group): class SphericalZoneSelection(Selection): - token = "sphzone" + token = 'sphzone' precedence = 1 def __init__(self, parser, tokens): @@ -427,9 +415,9 @@ def _apply(self, group): box = group.dimensions if self.periodic else None ref = sel.center_of_geometry().reshape(1, 3).astype(np.float32) - pairs = distances.capped_distance( - ref, group.positions, self.cutoff, box=box, return_distances=False - ) + pairs = distances.capped_distance(ref, group.positions, self.cutoff, + box=box, + return_distances=False) if pairs.size > 0: indices = np.sort(pairs[:, 1]) @@ -454,24 +442,21 @@ def _apply(self, group): "The diameter of the cylinder selection ({:.3f}) is larger " "than the unit cell's x dimension ({:.3f}). Can only do " "selections where it is smaller or equal." - "".format(2 * self.exRadius, box[0]) - ) + "".format(2*self.exRadius, box[0])) if 2 * self.exRadius > box[1]: raise NotImplementedError( "The diameter of the cylinder selection ({:.3f}) is larger " "than the unit cell's y dimension ({:.3f}). Can only do " "selections where it is smaller or equal." - "".format(2 * self.exRadius, box[1]) - ) + "".format(2*self.exRadius, box[1])) if cyl_z_hheight > box[2]: raise NotImplementedError( "The total length of the cylinder selection in z ({:.3f}) " "is larger than the unit cell's z dimension ({:.3f}). Can " "only do selections where it is smaller or equal." - "".format(cyl_z_hheight, box[2]) - ) + "".format(cyl_z_hheight, box[2])) - if np.all(group.dimensions[3:] == 90.0): + if np.all(group.dimensions[3:] == 90.): # Orthogonal version vecs -= box[:3] * np.rint(vecs / box[:3]) else: @@ -488,7 +473,7 @@ def _apply(self, group): group = group[mask] # Radial vectors from sel to each in group - radii = vecs[:, 0] ** 2 + vecs[:, 1] ** 2 + radii = vecs[:, 0]**2 + vecs[:, 1]**2 mask = radii < self.exRadius**2 try: mask &= radii > self.inRadius**2 @@ -500,7 +485,7 @@ def _apply(self, group): class CylindricalZoneSelection(CylindricalSelection): - token = "cyzone" + token = 'cyzone' precedence = 1 def __init__(self, parser, tokens): @@ -513,7 +498,7 @@ def __init__(self, parser, tokens): class CylindricalLayerSelection(CylindricalSelection): - token = "cylayer" + token = 'cylayer' precedence = 1 def __init__(self, parser, tokens): @@ -527,7 +512,7 @@ def __init__(self, parser, tokens): class PointSelection(Selection): - token = "point" + token = 'point' def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -543,13 +528,9 @@ def _apply(self, group): indices = [] box = group.dimensions if self.periodic else None - pairs = distances.capped_distance( - self.ref[None, :], - group.positions, - self.cutoff, - box=box, - return_distances=False, - ) + pairs = distances.capped_distance(self.ref[None, :], group.positions, self.cutoff, + box=box, + return_distances=False) if pairs.size > 0: indices = np.sort(pairs[:, 1]) @@ -557,7 +538,7 @@ def _apply(self, group): class AtomSelection(Selection): - token = "atom" + token = 'atom' def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -575,7 +556,7 @@ def _apply(self, group): class BondedSelection(Selection): - token = "bonded" + token = 'bonded' precedence = 1 def __init__(self, parser, tokens): @@ -606,16 +587,15 @@ def _apply(self, group): class SelgroupSelection(Selection): - token = "group" + token = 'group' def __init__(self, parser, tokens): super().__init__(parser, tokens) grpname = tokens.popleft() if grpname in _RESERVED_KWARGS: - raise TypeError( - "The '{}' keyword is reserved and cannot be " - "used as a selection group name.".format(grpname) - ) + raise TypeError("The '{}' keyword is reserved and cannot be " + "used as a selection group name." + .format(grpname)) try: self.grp = parser.selgroups[grpname] except KeyError: @@ -632,7 +612,6 @@ class SingleCharSelection(Selection): .. versionadded:: 2.1.0 """ - def __init__(self, parser, tokens): super().__init__(parser, tokens) vals = grab_not_keywords(tokens) @@ -656,7 +635,6 @@ class _ProtoStringSelection(Selection): .. versionchanged:: 1.0.0 Supports multiple wildcards, based on fnmatch """ - def __init__(self, parser, tokens): super().__init__(parser, tokens) vals = grab_not_keywords(tokens) @@ -687,9 +665,8 @@ class AromaticSelection(Selection): Aromaticity is available in the `aromaticities` attribute and is made available through RDKit""" - - token = "aromatic" - field = "aromaticities" + token = 'aromatic' + field = 'aromaticities' def _apply(self, group): return group[group.aromaticities] @@ -710,8 +687,7 @@ class SmartsSelection(Selection): limit cases where too few matches were generated. A warning is now also thrown if ``maxMatches`` has been reached. """ - - token = "smarts" + token = 'smarts' def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -744,12 +720,10 @@ def _apply(self, group): try: from rdkit import Chem except ImportError: - raise ImportError( - "RDKit is required for SMARTS-based atom " - "selection but it's not installed. Try " - "installing it with \n" - "conda install -c conda-forge rdkit" - ) + raise ImportError("RDKit is required for SMARTS-based atom " + "selection but it's not installed. Try " + "installing it with \n" + "conda install -c conda-forge rdkit") pattern = Chem.MolFromSmarts(self.pattern) if not pattern: raise ValueError(f"{self.pattern!r} is not a valid SMARTS query") @@ -758,16 +732,14 @@ def _apply(self, group): self.smarts_kwargs.setdefault("maxMatches", max(1000, len(group) * 10)) matches = mol.GetSubstructMatches(pattern, **self.smarts_kwargs) if len(matches) == self.smarts_kwargs["maxMatches"]: - warnings.warn( - "Your smarts-based atom selection returned the max" - "number of matches. This indicates that not all" - "matching atoms were selected. When calling" - "atom_group.select_atoms(), the default value" - "of maxMatches is max(100, len(atom_group * 10)). " - "To fix this, add the following argument to " - "select_atoms: \n" - "smarts_kwargs={maxMatches: }" - ) + warnings.warn("Your smarts-based atom selection returned the max" + "number of matches. This indicates that not all" + "matching atoms were selected. When calling" + "atom_group.select_atoms(), the default value" + "of maxMatches is max(100, len(atom_group * 10)). " + "To fix this, add the following argument to " + "select_atoms: \n" + "smarts_kwargs={maxMatches: }") # flatten all matches and remove duplicated indices indices = np.unique([idx for match in matches for idx in match]) # create boolean mask for atoms based on index @@ -783,8 +755,7 @@ class ResidSelection(Selection): resid 1:10 """ - - token = "resid" + token = 'resid' def __init__(self, parser, tokens): super().__init__(parser, tokens) @@ -831,11 +802,10 @@ def _apply(self, group): except (AttributeError, NoDataError): icodes = None # if no icodes and icodes are part of selection, cause a fuss - if any(v[1] for v in self.uppers) or any(v[1] for v in self.lowers): - errmsg = ( - "Selection specified icodes, while the topology " - "doesn't have any." - ) + if (any(v[1] for v in self.uppers) or + any(v[1] for v in self.lowers)): + errmsg = ("Selection specified icodes, while the topology " + "doesn't have any.") raise ValueError(errmsg) from None if not icodes is None: @@ -922,11 +892,9 @@ def __init__(self, parser, tokens): elif lower == "true": bval = True else: - raise ValueError( - f"'{val}' is an invalid value " - "for boolean selection. " - "Use 'True' or 'False'" - ) + raise ValueError(f"'{val}' is an invalid value " + "for boolean selection. " + "Use 'True' or 'False'") self.values.append(bval) def _apply(self, group): @@ -1008,27 +976,26 @@ def _apply(self, group): else: low, high = lower - 1, lower + 1 fp = "https://docs.python.org/3.8/tutorial/floatingpoint.html" - msg = ( - "Using float equality to select atoms is " - "not recommended because of inherent " - "limitations in representing numbers on " - f"computers (see {fp} for more). " - "Instead, we recommend using a range " - f"to select, e.g. '{self.token} {low} to {high}'. " - "If you still want to compare floats, use the " - "`atol` and `rtol` keywords to modify the tolerance " - "for `np.isclose`." - ) + msg = ("Using float equality to select atoms is " + "not recommended because of inherent " + "limitations in representing numbers on " + f"computers (see {fp} for more). " + "Instead, we recommend using a range " + f"to select, e.g. '{self.token} {low} to {high}'. " + "If you still want to compare floats, use the " + "`atol` and `rtol` keywords to modify the tolerance " + "for `np.isclose`.") warnings.warn(msg, category=SelectionWarning) - thismask = np.isclose(vals, lower, atol=self.atol, rtol=self.rtol) + thismask = np.isclose(vals, lower, atol=self.atol, + rtol=self.rtol) mask |= thismask return group[mask] class ByNumSelection(RangeSelection): - token = "bynum" - field = "indices" + token = 'bynum' + field = 'indices' value_offset = 1 # queries are in 1 based indices @@ -1051,129 +1018,38 @@ class ProteinSelection(Selection): prot_res changed to set (from numpy array) performance improved by ~100x on larger systems """ - - token = "protein" + token = 'protein' prot_res = { # CHARMM top_all27_prot_lipid.rtf - "ALA", - "ARG", - "ASN", - "ASP", - "CYS", - "GLN", - "GLU", - "GLY", - "HSD", - "HSE", - "HSP", - "ILE", - "LEU", - "LYS", - "MET", - "PHE", - "PRO", - "SER", - "THR", - "TRP", - "TYR", - "VAL", - "ALAD", + 'ALA', 'ARG', 'ASN', 'ASP', 'CYS', 'GLN', 'GLU', 'GLY', 'HSD', + 'HSE', 'HSP', 'ILE', 'LEU', 'LYS', 'MET', 'PHE', 'PRO', 'SER', 'THR', + 'TRP', 'TYR', 'VAL', 'ALAD', ## 'CHO','EAM', # -- special formyl and ethanolamine termini of gramicidin # PDB - "HIS", - "MSE", + 'HIS', 'MSE', # from Gromacs 4.5.3 oplsaa.ff/aminoacids.rtp - "ARGN", - "ASPH", - "CYS2", - "CYSH", - "QLN", - "PGLU", - "GLUH", - "HIS1", - "HISD", - "HISE", - "HISH", - "LYSH", + 'ARGN', 'ASPH', 'CYS2', 'CYSH', 'QLN', 'PGLU', 'GLUH', 'HIS1', 'HISD', + 'HISE', 'HISH', 'LYSH', # from Gromacs 4.5.3 gromos53a6.ff/aminoacids.rtp - "ASN1", - "CYS1", - "HISA", - "HISB", - "HIS2", + 'ASN1', 'CYS1', 'HISA', 'HISB', 'HIS2', # from Gromacs 4.5.3 amber03.ff/aminoacids.rtp - "HID", - "HIE", - "HIP", - "ORN", - "DAB", - "LYN", - "HYP", - "CYM", - "CYX", - "ASH", - "GLH", - "ACE", - "NME", + 'HID', 'HIE', 'HIP', 'ORN', 'DAB', 'LYN', 'HYP', 'CYM', 'CYX', 'ASH', + 'GLH', 'ACE', 'NME', # from Gromacs 2016.3 amber99sb-star-ildn.ff/aminoacids.rtp - "NALA", - "NGLY", - "NSER", - "NTHR", - "NLEU", - "NILE", - "NVAL", - "NASN", - "NGLN", - "NARG", - "NHID", - "NHIE", - "NHIP", - "NTRP", - "NPHE", - "NTYR", - "NGLU", - "NASP", - "NLYS", - "NPRO", - "NCYS", - "NCYX", - "NMET", - "CALA", - "CGLY", - "CSER", - "CTHR", - "CLEU", - "CILE", - "CVAL", - "CASF", - "CASN", - "CGLN", - "CARG", - "CHID", - "CHIE", - "CHIP", - "CTRP", - "CPHE", - "CTYR", - "CGLU", - "CASP", - "CLYS", - "CPRO", - "CCYS", - "CCYX", - "CMET", - "CME", - "ASF", + 'NALA', 'NGLY', 'NSER', 'NTHR', 'NLEU', 'NILE', 'NVAL', 'NASN', 'NGLN', + 'NARG', 'NHID', 'NHIE', 'NHIP', 'NTRP', 'NPHE', 'NTYR', 'NGLU', 'NASP', + 'NLYS', 'NPRO', 'NCYS', 'NCYX', 'NMET', 'CALA', 'CGLY', 'CSER', 'CTHR', + 'CLEU', 'CILE', 'CVAL', 'CASF', 'CASN', 'CGLN', 'CARG', 'CHID', 'CHIE', + 'CHIP', 'CTRP', 'CPHE', 'CTYR', 'CGLU', 'CASP', 'CLYS', 'CPRO', 'CCYS', + 'CCYX', 'CMET', 'CME', 'ASF', } def _apply(self, group): resname_attr = group.universe._topology.resnames # which values in resname attr are in prot_res? - matches = [ - ix for (nm, ix) in resname_attr.namedict.items() if nm in self.prot_res - ] + matches = [ix for (nm, ix) in resname_attr.namedict.items() + if nm in self.prot_res] # index of each atom's resname nmidx = resname_attr.nmidx[group.resindices] # intersect atom's resname index and matches to prot_res @@ -1196,51 +1072,23 @@ class NucleicSelection(Selection): nucl_res changed to set (from numpy array) performance improved by ~100x on larger systems """ - - token = "nucleic" + token = 'nucleic' nucl_res = { - "ADE", - "URA", - "CYT", - "GUA", - "THY", - "DA", - "DC", - "DG", - "DT", - "RA", - "RU", - "RG", - "RC", - "A", - "T", - "U", - "C", - "G", - "DA5", - "DC5", - "DG5", - "DT5", - "DA3", - "DC3", - "DG3", - "DT3", - "RA5", - "RU5", - "RG5", - "RC5", - "RA3", - "RU3", - "RG3", - "RC3", + 'ADE', 'URA', 'CYT', 'GUA', 'THY', 'DA', 'DC', 'DG', 'DT', 'RA', + 'RU', 'RG', 'RC', 'A', 'T', 'U', 'C', 'G', + 'DA5', 'DC5', 'DG5', 'DT5', + 'DA3', 'DC3', 'DG3', 'DT3', + 'RA5', 'RU5', 'RG5', 'RC5', + 'RA3', 'RU3', 'RG3', 'RC3' } def _apply(self, group): resnames = group.universe._topology.resnames nmidx = resnames.nmidx[group.resindices] - matches = [ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res] + matches = [ix for (nm, ix) in resnames.namedict.items() + if nm in self.nucl_res] mask = np.isin(nmidx, matches) return group[mask] @@ -1283,7 +1131,11 @@ def _apply(self, group): resnames = group.universe._topology.resnames nmidx = resnames.nmidx[group.resindices] - matches = [ix for (nm, ix) in resnames.namedict.items() if nm in self.water_res] + matches = [ + ix + for (nm, ix) in resnames.namedict.items() + if nm in self.water_res + ] mask = np.isin(nmidx, matches) return group[mask] @@ -1300,25 +1152,22 @@ class BackboneSelection(ProteinSelection): bb_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - - token = "backbone" - bb_atoms = {"N", "CA", "C", "O"} + token = 'backbone' + bb_atoms = {'N', 'CA', 'C', 'O'} def _apply(self, group): atomnames = group.universe._topology.names resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ - ix for (nm, ix) in atomnames.namedict.items() if nm in self.bb_atoms - ] + name_matches = [ix for (nm, ix) in atomnames.namedict.items() + if nm in self.bb_atoms] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ - ix for (nm, ix) in resnames.namedict.items() if nm in self.prot_res - ] + resname_matches = [ix for (nm, ix) in resnames.namedict.items() + if nm in self.prot_res] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1336,8 +1185,7 @@ class NucleicBackboneSelection(NucleicSelection): bb_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - - token = "nucleicbackbone" + token = 'nucleicbackbone' bb_atoms = {"P", "C5'", "C3'", "O3'", "O5'"} def _apply(self, group): @@ -1345,16 +1193,14 @@ def _apply(self, group): resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ - ix for (nm, ix) in atomnames.namedict.items() if nm in self.bb_atoms - ] + name_matches = [ix for (nm, ix) in atomnames.namedict.items() + if nm in self.bb_atoms] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ - ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res - ] + resname_matches = [ix for (nm, ix) in resnames.namedict.items() + if nm in self.nucl_res] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1374,42 +1220,25 @@ class BaseSelection(NucleicSelection): base_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - - token = "nucleicbase" + token = 'nucleicbase' base_atoms = { - "N9", - "N7", - "C8", - "C5", - "C4", - "N3", - "C2", - "N1", - "C6", - "O6", - "N2", - "N6", - "O2", - "N4", - "O4", - "C5M", - } + 'N9', 'N7', 'C8', 'C5', 'C4', 'N3', 'C2', 'N1', 'C6', + 'O6', 'N2', 'N6', + 'O2', 'N4', 'O4', 'C5M'} def _apply(self, group): atomnames = group.universe._topology.names resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ - ix for (nm, ix) in atomnames.namedict.items() if nm in self.base_atoms - ] + name_matches = [ix for (nm, ix) in atomnames.namedict.items() + if nm in self.base_atoms] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ - ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res - ] + resname_matches = [ix for (nm, ix) in resnames.namedict.items() + if nm in self.nucl_res] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1424,8 +1253,7 @@ class NucleicSugarSelection(NucleicSelection): sug_atoms changed to set (from numpy array) performance improved by ~100x on larger systems """ - - token = "nucleicsugar" + token = 'nucleicsugar' sug_atoms = {"C1'", "C2'", "C3'", "C4'", "O4'"} def _apply(self, group): @@ -1433,16 +1261,14 @@ def _apply(self, group): resnames = group.universe._topology.resnames # filter by atom names - name_matches = [ - ix for (nm, ix) in atomnames.namedict.items() if nm in self.sug_atoms - ] + name_matches = [ix for (nm, ix) in atomnames.namedict.items() + if nm in self.sug_atoms] nmidx = atomnames.nmidx[group.ix] group = group[np.isin(nmidx, name_matches)] # filter by resnames - resname_matches = [ - ix for (nm, ix) in resnames.namedict.items() if nm in self.nucl_res - ] + resname_matches = [ix for (nm, ix) in resnames.namedict.items() + if nm in self.nucl_res] nmidx = resnames.nmidx[group.resindices] group = group[np.isin(nmidx, resname_matches)] @@ -1458,34 +1284,30 @@ class PropertySelection(Selection): Added ``atol`` and ``rtol`` keywords to control ``np.isclose`` tolerance. """ - - token = "prop" - ops = dict( - [ - (">", np.greater), - ("<", np.less), - (">=", np.greater_equal), - ("<=", np.less_equal), - ("==", np.isclose), - ("!=", np.not_equal), - ] - ) + token = 'prop' + ops = dict([ + ('>', np.greater), + ('<', np.less), + ('>=', np.greater_equal), + ('<=', np.less_equal), + ('==', np.isclose), + ('!=', np.not_equal), + ]) # order here is important, need to check <= before < so the # larger (in terms of string length) symbol is considered first - _op_symbols = ("<=", ">=", "==", "!=", "<", ">") + _op_symbols = ('<=', '>=', '==', '!=', '<', '>') # symbols to replace with when flipping # eg 6 > x -> x <= 6, 5 == x -> x == 5 opposite_ops = { - "==": "==", - "!=": "!=", - "<": ">=", - ">=": "<", - ">": "<=", - "<=": ">", + '==': '==', '!=': '!=', + '<': '>=', '>=': '<', + '>': '<=', '<=': '>', } - props = {"x": "positions", "y": "positions", "z": "positions"} + props = {"x": "positions", + "y": "positions", + "z": "positions"} def __init__(self, parser, tokens): """ @@ -1543,13 +1365,14 @@ def __init__(self, parser, tokens): try: self.operator = self.ops[oper] except KeyError: - errmsg = f"Invalid operator : '{oper}' Use one of : " f"'{self.ops.keys()}'" + errmsg = (f"Invalid operator : '{oper}' Use one of : " + f"'{self.ops.keys()}'") raise ValueError(errmsg) from None else: if oper == "==": - self.operator = functools.partial( - self.operator, atol=parser.atol, rtol=parser.rtol - ) + self.operator = functools.partial(self.operator, + atol=parser.atol, + rtol=parser.rtol) self.value = float(value) def _apply(self, group): @@ -1564,7 +1387,7 @@ def _apply(self, group): raise SelectionError(errmsg) from None try: - col = {"x": 0, "y": 1, "z": 2}[self.prop] + col = {'x': 0, 'y': 1, 'z': 2}[self.prop] except KeyError: pass else: @@ -1586,26 +1409,26 @@ class SameSelection(Selection): :code:`"segindices"` (see #2669 and #2672) """ - token = "same" + token = 'same' precedence = 1 prop_trans = { - "fragment": None, - "x": None, - "y": None, - "z": None, - "residue": "resindices", - "segment": "segindices", - "name": "names", - "type": "types", - "resname": "resnames", - "resid": "resids", - "segid": "segids", - "mass": "masses", - "charge": "charges", - "radius": "radii", - "bfactor": "bfactors", - "resnum": "resnums", + 'fragment': None, + 'x': None, + 'y': None, + 'z': None, + 'residue': 'resindices', + 'segment': 'segindices', + 'name': 'names', + 'type': 'types', + 'resname': 'resnames', + 'resid': 'resids', + 'segid': 'segids', + 'mass': 'masses', + 'charge': 'charges', + 'radius': 'radii', + 'bfactor': 'bfactors', + 'resnum': 'resnums', } def __init__(self, parser, tokens): @@ -1613,11 +1436,9 @@ def __init__(self, parser, tokens): prop = tokens.popleft() if prop not in self.prop_trans: - raise ValueError( - "Unknown same property : {0}" - "Choose one of : {1}" - "".format(prop, self.prop_trans.keys()) - ) + raise ValueError("Unknown same property : {0}" + "Choose one of : {1}" + "".format(prop, self.prop_trans.keys())) self.prop = prop parser.expect("as") self.sel = parser.parse_expression(self.precedence) @@ -1629,7 +1450,7 @@ def _apply(self, group): return group[[]] # empty selection # Fragment must come before self.prop_trans lookups! - if self.prop == "fragment": + if self.prop == 'fragment': # Combine all fragments together, then check where group # indices are same as fragment(s) indices allfrags = functools.reduce(lambda x, y: x + y, res.fragments) @@ -1638,7 +1459,7 @@ def _apply(self, group): return group[mask] # [xyz] must come before self.prop_trans lookups too! try: - pos_idx = {"x": 0, "y": 1, "z": 2}[self.prop] + pos_idx = {'x': 0, 'y': 1, 'z': 2}[self.prop] except KeyError: # The self.prop string was already checked, # so don't need error checking here. @@ -1653,7 +1474,8 @@ def _apply(self, group): pos = group.positions[:, pos_idx] # isclose only does one value at a time - mask = np.vstack([np.isclose(pos, v) for v in vals]).any(axis=0) + mask = np.vstack([np.isclose(pos, v) + for v in vals]).any(axis=0) return group[mask] @@ -1675,8 +1497,7 @@ class SelectionParser(object): | resid [value] | name [value] | type [value] - """ - + """ # Borg pattern: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531 _shared_state = {} @@ -1692,20 +1513,10 @@ def expect(self, token): else: raise SelectionError( "Unexpected token: '{0}' Expected: '{1}'" - "".format(self.tokens[0], token) - ) - - def parse( - self, - selectstr, - selgroups, - periodic=None, - atol=1e-08, - rtol=1e-05, - sorted=True, - rdkit_kwargs=None, - smarts_kwargs=None, - ): + "".format(self.tokens[0], token)) + + def parse(self, selectstr, selgroups, periodic=None, atol=1e-08, + rtol=1e-05, sorted=True, rdkit_kwargs=None, smarts_kwargs=None): """Create a Selection object from a string. Parameters @@ -1759,22 +1570,19 @@ def parse( self.selectstr = selectstr self.selgroups = selgroups - tokens = selectstr.replace("(", " ( ").replace(")", " ) ") + tokens = selectstr.replace('(', ' ( ').replace(')', ' ) ') self.tokens = collections.deque(tokens.split() + [None]) parsetree = self.parse_expression(0) if self.tokens[0] is not None: raise SelectionError( "Unexpected token at end of selection string: '{0}'" - "".format(self.tokens[0]) - ) + "".format(self.tokens[0])) return parsetree def parse_expression(self, p): exp1 = self._parse_subexp() - while ( - self.tokens[0] in _OPERATIONS - and _OPERATIONS[self.tokens[0]].precedence >= p - ): + while (self.tokens[0] in _OPERATIONS and + _OPERATIONS[self.tokens[0]].precedence >= p): op = _OPERATIONS[self.tokens.popleft()] q = 1 + op.precedence exp2 = self.parse_expression(q) @@ -1784,9 +1592,9 @@ def parse_expression(self, p): def _parse_subexp(self): op = self.tokens.popleft() - if op == "(": + if op == '(': exp = self.parse_expression(0) - self.expect(")") + self.expect(')') return exp try: @@ -1803,9 +1611,8 @@ def _parse_subexp(self): Parser = SelectionParser() # create a module container to avoid name clashes of autogenerated classes -_selectors = types.ModuleType( - f"{__name__}._selectors", doc="Automatically generated selectors" -) +_selectors = types.ModuleType(f"{__name__}._selectors", + doc="Automatically generated selectors") # stick it in sys.modules so pickle can find it sys.modules[_selectors.__name__] = _selectors @@ -1860,7 +1667,7 @@ def gen_selection_class(singular, attrname, dtype, per_object): >>> gen_selection_class("resname", "resnames", object, "residue") - + Simply generating this selector is sufficient for the keyword to be accessible by :meth:`~MDAnalysis.core.universe.Universe.select_atoms`, as that is automatically handled by @@ -1872,15 +1679,12 @@ def gen_selection_class(singular, attrname, dtype, per_object): .. versionadded:: 2.0.0 """ - basedct = { - "token": singular, - "field": attrname, - # manually make modules the _selectors wrapper - "__module__": _selectors.__name__, - } + basedct = {"token": singular, "field": attrname, + # manually make modules the _selectors wrapper + "__module__": _selectors.__name__} name = f"{singular.capitalize()}Selection" - if dtype == "U1": # order is important here, U1 will trip up issubclass + if dtype == 'U1': # order is important here, U1 will trip up issubclass basecls = SingleCharSelection elif issubclass(dtype, bool): basecls = BoolSelection @@ -1897,11 +1701,9 @@ def gen_selection_class(singular, attrname, dtype, per_object): else: basedct["level"] = "ix" else: - raise ValueError( - f"No base class defined for dtype {dtype}. " - "Define a Selection class manually by " - "subclassing core.selection.Selection" - ) + raise ValueError(f"No base class defined for dtype {dtype}. " + "Define a Selection class manually by " + "subclassing core.selection.Selection") cls = type(name, (basecls,), basedct) setattr(_selectors, name, cls) # stick it in _selectors diff --git a/package/MDAnalysis/core/topology.py b/package/MDAnalysis/core/topology.py index 59275a8314..dffff294d3 100644 --- a/package/MDAnalysis/core/topology.py +++ b/package/MDAnalysis/core/topology.py @@ -601,7 +601,10 @@ def add_Residue(self, segment, **new_attrs): missing = ( attr.singular for attr in self.attrs - if (attr.per_object == "residue" and attr.singular not in new_attrs) + if ( + attr.per_object == "residue" + and attr.singular not in new_attrs + ) ) raise NoDataError( "Missing the following attributes for the new" diff --git a/package/MDAnalysis/core/topologyattrs.py b/package/MDAnalysis/core/topologyattrs.py index 83a5ee10e1..359bd20c9c 100644 --- a/package/MDAnalysis/core/topologyattrs.py +++ b/package/MDAnalysis/core/topologyattrs.py @@ -396,7 +396,9 @@ def __init__(cls, name, bases, classdict): if dtype is not None: per_obj = classdict.get("per_object", bases[0].per_object) try: - selection.gen_selection_class(singular, attrname, dtype, per_obj) + selection.gen_selection_class( + singular, attrname, dtype, per_obj + ) except ValueError: msg = ( "A selection keyword could not be " @@ -474,7 +476,9 @@ def _gen_initial_values(n_atoms, n_residues, n_segments): raise NotImplementedError("No default values") @classmethod - def from_blank(cls, n_atoms=None, n_residues=None, n_segments=None, values=None): + def from_blank( + cls, n_atoms=None, n_residues=None, n_segments=None, values=None + ): """Create a blank version of this TopologyAttribute Parameters @@ -825,7 +829,9 @@ def _set_X(self, ag, values): newnames.append(val) newidx[i] = nextidx - self.nmidx[ag.ix] = newidx # newidx either single value or same size array + self.nmidx[ag.ix] = ( + newidx # newidx either single value or same size array + ) if newnames: self.name_lookup = np.concatenate([self.name_lookup, newnames]) self.values = self.name_lookup[self.nmidx] @@ -948,7 +954,8 @@ def phi_selections(residues, c_name="C", n_name="N", ca_name="CA"): keep_prev = [sum(r.atoms.names == c_name) == 1 for r in prev] keep_res = [ - all(sum(r.atoms.names == n) == 1 for n in ncac_names) for r in residues + all(sum(r.atoms.names == n) == 1 for n in ncac_names) + for r in residues ] keep = np.array(keep_prev) & np.array(keep_res) keep[invalid] = False @@ -1139,7 +1146,8 @@ def psi_selections(residues, c_name="C", n_name="N", ca_name="CA"): keep_nxt = [sum(r.atoms.names == n_name) == 1 for r in nxt] keep_res = [ - all(sum(r.atoms.names == n) == 1 for n in ncac_names) for r in residues + all(sum(r.atoms.names == n) == 1 for n in ncac_names) + for r in residues ] keep = np.array(keep_nxt) & np.array(keep_res) nxt = nxt[keep] @@ -1251,9 +1259,12 @@ def omega_selections(residues, c_name="C", n_name="N", ca_name="CA"): nxtatoms = [ca_name, n_name] resatoms = [ca_name, c_name] - keep_nxt = [all(sum(r.atoms.names == n) == 1 for n in nxtatoms) for r in nxt] + keep_nxt = [ + all(sum(r.atoms.names == n) == 1 for n in nxtatoms) for r in nxt + ] keep_res = [ - all(sum(r.atoms.names == n) == 1 for n in resatoms) for r in residues + all(sum(r.atoms.names == n) == 1 for n in resatoms) + for r in residues ] keep = np.array(keep_nxt) & np.array(keep_res) nxt = nxt[keep] @@ -1755,9 +1766,13 @@ def moment_of_inertia(group, wrap=False, unwrap=False, compound="group"): """ atomgroup = group.atoms - com = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) + com = atomgroup.center_of_mass( + wrap=wrap, unwrap=unwrap, compound=compound + ) if compound != "group": - com = (com * group.masses[:, None]).sum(axis=0) / group.masses.sum() + com = (com * group.masses[:, None]).sum( + axis=0 + ) / group.masses.sum() if wrap: pos = atomgroup.pack_into_box(inplace=False) - com @@ -1888,7 +1903,9 @@ def _gyration(recenteredpos, masses): atomgroup = group.atoms masses = atomgroup.masses - com = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) + com = atomgroup.center_of_mass( + wrap=wrap, unwrap=unwrap, compound=compound + ) if compound == "group": if wrap: @@ -2023,7 +2040,8 @@ def asphericity(group, wrap=False, unwrap=False, compound="group"): ) else: shape = (3.0 / 2.0) * ( - np.sum((eig_vals - np.mean(eig_vals)) ** 2) / np.sum(eig_vals) ** 2 + np.sum((eig_vals - np.mean(eig_vals)) ** 2) + / np.sum(eig_vals) ** 2 ) return shape @@ -2107,7 +2125,9 @@ def align_principal_axis(group, axis, vector): # print "axis = %r, angle = %f deg" % (ax, angle) return group.rotateby(angle, ax) - transplants[GroupBase].append(("align_principal_axis", align_principal_axis)) + transplants[GroupBase].append( + ("align_principal_axis", align_principal_axis) + ) # TODO: update docs to property doc @@ -2264,7 +2284,9 @@ def total_charge(group, compound="group"): @warn_if_not_unique @_pbc_to_wrap @check_wrap_and_unwrap - def dipole_vector(group, wrap=False, unwrap=False, compound="group", center="mass"): + def dipole_vector( + group, wrap=False, unwrap=False, compound="group", center="mass" + ): r"""Dipole vector of the group. .. math:: @@ -2330,7 +2352,9 @@ def dipole_vector(group, wrap=False, unwrap=False, compound="group", center="mas if center == "mass": masses = atomgroup.masses - ref = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) + ref = atomgroup.center_of_mass( + wrap=wrap, unwrap=unwrap, compound=compound + ) elif center == "charge": ref = atomgroup.center_of_charge( wrap=wrap, unwrap=unwrap, compound=compound @@ -2356,7 +2380,9 @@ def dipole_vector(group, wrap=False, unwrap=False, compound="group", center="mas ) else: recenteredpos = atomgroup.positions - ref - dipole_vector = np.einsum("ij,ij->j", recenteredpos, charges[:, np.newaxis]) + dipole_vector = np.einsum( + "ij,ij->j", recenteredpos, charges[:, np.newaxis] + ) else: (atom_masks, compound_masks, n_compounds) = ( atomgroup._split_by_compound_indices(compound) @@ -2440,9 +2466,13 @@ def dipole_moment(group, **kwargs): dipole_vector = atomgroup.dipole_vector(**kwargs) if len(dipole_vector.shape) > 1: - dipole_moment = np.sqrt(np.einsum("ij,ij->i", dipole_vector, dipole_vector)) + dipole_moment = np.sqrt( + np.einsum("ij,ij->i", dipole_vector, dipole_vector) + ) else: - dipole_moment = np.sqrt(np.einsum("i,i->", dipole_vector, dipole_vector)) + dipole_moment = np.sqrt( + np.einsum("i,i->", dipole_vector, dipole_vector) + ) return dipole_moment @@ -2535,7 +2565,9 @@ def __quadrupole_tensor(recenteredpos, charges): if center == "mass": masses = atomgroup.masses - ref = atomgroup.center_of_mass(wrap=wrap, unwrap=unwrap, compound=compound) + ref = atomgroup.center_of_mass( + wrap=wrap, unwrap=unwrap, compound=compound + ) elif center == "charge": ref = atomgroup.center_of_charge( wrap=wrap, unwrap=unwrap, compound=compound @@ -2653,7 +2685,9 @@ def __quadrupole_moment(tensor): if len(quad_tensor.shape) == 2: quad_moment = __quadrupole_moment(quad_tensor) else: - quad_moment = np.array([__quadrupole_moment(x) for x in quad_tensor]) + quad_moment = np.array( + [__quadrupole_moment(x) for x in quad_tensor] + ) return quad_moment @@ -2977,7 +3011,9 @@ def sequence(self, **kwargs): ) ) try: - sequence = "".join([convert_aa_code(r) for r in self.residues.resnames]) + sequence = "".join( + [convert_aa_code(r) for r in self.residues.resnames] + ) except KeyError as err: errmsg = ( f"AtomGroup contains a residue name '{err.message}' that" @@ -3110,13 +3146,14 @@ def _check_connection_values(func): @functools.wraps(func) def wrapper(self, values, *args, **kwargs): if not all( - len(x) == self._n_atoms and all(isinstance(y, (int, np.integer)) for y in x) + len(x) == self._n_atoms + and all(isinstance(y, (int, np.integer)) for y in x) for x in values ): raise ValueError( - ("{} must be an iterable of tuples with {}" " atom indices").format( - self.attrname, self._n_atoms - ) + ( + "{} must be an iterable of tuples with {}" " atom indices" + ).format(self.attrname, self._n_atoms) ) clean = [] for v in values: @@ -3194,7 +3231,9 @@ def _bondDict(self): """Lazily built mapping of atoms:bonds""" bd = defaultdict(list) - for b, t, g, o in zip(self.values, self.types, self._guessed, self.order): + for b, t, g, o in zip( + self.values, self.types, self._guessed, self.order + ): for a in b: bd[a].append((b, t, g, o)) return bd @@ -3213,7 +3252,9 @@ def get_atoms(self, ag): """ try: - unique_bonds = set(itertools.chain(*[self._bondDict[a] for a in ag.ix])) + unique_bonds = set( + itertools.chain(*[self._bondDict[a] for a in ag.ix]) + ) except TypeError: # maybe we got passed an Atom unique_bonds = self._bondDict[ag.ix] diff --git a/package/MDAnalysis/core/topologyobjects.py b/package/MDAnalysis/core/topologyobjects.py index 14d44a4c8c..fcc37be624 100644 --- a/package/MDAnalysis/core/topologyobjects.py +++ b/package/MDAnalysis/core/topologyobjects.py @@ -603,7 +603,9 @@ def __init__( # guess what I am # difference between dihedral and improper # not really important - self.btype = {2: "bond", 3: "angle", 4: "dihedral"}[len(bondidx[0])] + self.btype = {2: "bond", 3: "angle", 4: "dihedral"}[ + len(bondidx[0]) + ] elif btype in _BTYPE_TO_SHAPE: self.btype = btype else: @@ -636,7 +638,8 @@ def __init__( # Create vertical AtomGroups self._ags = [ - universe.atoms[self._bix[:, i]] for i in range(self._bix.shape[1]) + universe.atoms[self._bix[:, i]] + for i in range(self._bix.shape[1]) ] else: # Empty TopologyGroup @@ -813,11 +816,15 @@ def __add__(self, other): np.concatenate([self.indices, other.indices[None, :]]), self.universe, btype=self.btype, - type=np.concatenate([self._bondtypes, np.array([other._bondtype])]), + type=np.concatenate( + [self._bondtypes, np.array([other._bondtype])] + ), guessed=np.concatenate( [self._guessed, np.array([other.is_guessed])] ), - order=np.concatenate([self._order, np.array([other.order])]), + order=np.concatenate( + [self._order, np.array([other.order])] + ), ) else: # add TG to me diff --git a/package/MDAnalysis/core/universe.py b/package/MDAnalysis/core/universe.py index e315c8dc70..6dbc063f10 100644 --- a/package/MDAnalysis/core/universe.py +++ b/package/MDAnalysis/core/universe.py @@ -80,28 +80,14 @@ from ..lib.mdamath import find_fragments from . import groups from ._get_readers import get_reader_for, get_parser_for -from .groups import ( - ComponentBase, - GroupBase, - Atom, - Residue, - Segment, - AtomGroup, - ResidueGroup, - SegmentGroup, -) +from .groups import (ComponentBase, GroupBase, + Atom, Residue, Segment, + AtomGroup, ResidueGroup, SegmentGroup) from .topology import Topology from .topologyattrs import ( - AtomAttr, - ResidueAttr, - SegmentAttr, - Segindices, - Segids, - Resindices, - Resids, - Atomindices, - BFACTOR_WARNING, - _Connection, + AtomAttr, ResidueAttr, SegmentAttr, + Segindices, Segids, Resindices, Resids, Atomindices, + BFACTOR_WARNING, _Connection ) from .topologyobjects import TopologyObject from ..guesser.base import get_guesser @@ -130,8 +116,8 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): atom_attrindices = [ idx for idx, each_attr in enumerate(top.attrs) - if (Residue not in each_attr.target_classes) - and (not isinstance(each_attr, Atomindices)) + if (Residue not in each_attr.target_classes) and + (not isinstance(each_attr, Atomindices)) ] attrs = [top.attrs[each_attr] for each_attr in atom_attrindices] @@ -140,17 +126,17 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): idx for idx, each_attr in enumerate(top.attrs) if ( - (Residue in each_attr.target_classes) - and (Segment not in each_attr.target_classes) - and (not isinstance(each_attr, Resids)) - and (not isinstance(each_attr, Resindices)) + (Residue in each_attr.target_classes) and + (Segment not in each_attr.target_classes) and + (not isinstance(each_attr, Resids)) and + (not isinstance(each_attr, Resindices)) ) ] # residue level attributes except resids and resindices res_criteria = [atomwise_resids, atomwise_segids] + [ getattr(universe.atoms, top.attrs[each_attr].attrname) for each_attr in residue_attrindices - if top.attrs[each_attr].attrname != "resnums" + if top.attrs[each_attr].attrname != 'resnums' ] res_to_squash = [atomwise_resids, atomwise_segids] + [ @@ -182,11 +168,11 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): each_attr for each_attr in top.attrs if ( - (Segment in each_attr.target_classes) - and (not isinstance(each_attr, Segids)) - and (not isinstance(each_attr, Atomindices)) - and (not isinstance(each_attr, Resindices)) - and (not isinstance(each_attr, Segindices)) + (Segment in each_attr.target_classes) and + (not isinstance(each_attr, Segids)) and + (not isinstance(each_attr, Atomindices)) and + (not isinstance(each_attr, Resindices)) and + (not isinstance(each_attr, Segindices)) ) ] @@ -211,15 +197,15 @@ def _update_topology_by_ids(universe, atomwise_resids, atomwise_segids): def _check_file_like(topology): if isstream(topology): - if hasattr(topology, "name"): + if hasattr(topology, 'name'): _name = topology.name else: _name = None return NamedStream(topology, _name) return topology - -def _topology_from_file_like(topology_file, topology_format=None, **kwargs): +def _topology_from_file_like(topology_file, topology_format=None, + **kwargs): parser = get_parser_for(topology_file, format=topology_format) try: @@ -229,22 +215,20 @@ def _topology_from_file_like(topology_file, topology_format=None, **kwargs): # There are 2 kinds of errors that might be raised here: # one because the file isn't present # or the permissions are bad, second when the parser fails - if err.errno is not None and errno.errorcode[err.errno] in ["ENOENT", "EACCES"]: + if (err.errno is not None and + errno.errorcode[err.errno] in ['ENOENT', 'EACCES']): # Runs if the error is propagated due to no permission / file not found raise sys.exc_info()[1] from err else: # Runs when the parser fails - raise IOError( - "Failed to load from the topology file {0}" - " with parser {1}.\n" - "Error: {2}".format(topology_file, parser, err) - ) + raise IOError("Failed to load from the topology file {0}" + " with parser {1}.\n" + "Error: {2}".format(topology_file, parser, err)) except (ValueError, NotImplementedError) as err: raise ValueError( "Failed to construct topology from file {0}" " with parser {1}.\n" - "Error: {2}".format(topology_file, parser, err) - ) + "Error: {2}".format(topology_file, parser, err)) return topology @@ -257,20 +241,18 @@ def _resolve_formats(*coordinates, format=None, topology_format=None): return format, topology_format -def _resolve_coordinates(filename, *coordinates, format=None, all_coordinates=False): +def _resolve_coordinates(filename, *coordinates, format=None, + all_coordinates=False): if all_coordinates or not coordinates and filename is not None: try: get_reader_for(filename, format=format) except (ValueError, TypeError): - warnings.warn( - "No coordinate reader found for {}. Skipping " - "this file.".format(filename) - ) + warnings.warn('No coordinate reader found for {}. Skipping ' + 'this file.'.format(filename)) else: coordinates = (filename,) + coordinates return coordinates - def _generate_from_topology(universe): # generate Universe version of each class # AG, RG, SG, A, R, S @@ -288,9 +270,11 @@ def _generate_from_topology(universe): # once.) universe.atoms = AtomGroup(np.arange(universe._topology.n_atoms), universe) - universe.residues = ResidueGroup(np.arange(universe._topology.n_residues), universe) + universe.residues = ResidueGroup( + np.arange(universe._topology.n_residues), universe) - universe.segments = SegmentGroup(np.arange(universe._topology.n_segments), universe) + universe.segments = SegmentGroup( + np.arange(universe._topology.n_segments), universe) class Universe(object): @@ -412,7 +396,7 @@ class Universe(object): method instead. If passed into `guess_TopologyAttrs`, it will override the values set during Guesser creation. - + transformations: function or list, ``None``, default ``None`` Provide a list of transformations that you wish to apply to the trajectory upon reading. Transformations can be found in @@ -507,82 +491,60 @@ class Universe(object): API to set residues/segments based on the atomwise resids/segids. """ - - def __init__( - self, - topology=None, - *coordinates, - all_coordinates=False, - format=None, - topology_format=None, - transformations=None, - guess_bonds=False, - vdwradii=None, - fudge_factor=0.55, - lower_bound=0.1, - in_memory=False, - context="default", - to_guess=("types", "masses"), - force_guess=(), - in_memory_step=1, - **kwargs, - ): + def __init__(self, topology=None, *coordinates, all_coordinates=False, + format=None, topology_format=None, transformations=None, + guess_bonds=False, vdwradii=None, fudge_factor=0.55, + lower_bound=0.1, in_memory=False, context='default', + to_guess=('types', 'masses'), force_guess=(), + in_memory_step=1, **kwargs): self._trajectory = None # managed attribute holding Reader - self._cache = {"_valid": {}} + self._cache = {'_valid': {}} self.atoms = None self.residues = None self.segments = None self.filename = None self._context = get_guesser(context) self._kwargs = { - "transformations": transformations, - "guess_bonds": guess_bonds, - "vdwradii": vdwradii, - "fudge_factor": fudge_factor, - "lower_bound": lower_bound, - "in_memory": in_memory, - "in_memory_step": in_memory_step, - "format": format, - "topology_format": topology_format, - "all_coordinates": all_coordinates, + 'transformations': transformations, + 'guess_bonds': guess_bonds, + 'vdwradii': vdwradii, + 'fudge_factor': fudge_factor, + 'lower_bound': lower_bound, + 'in_memory': in_memory, + 'in_memory_step': in_memory_step, + 'format': format, + 'topology_format': topology_format, + 'all_coordinates': all_coordinates } self._kwargs.update(kwargs) - format, topology_format = _resolve_formats( - *coordinates, format=format, topology_format=topology_format - ) + format, topology_format = _resolve_formats(*coordinates, format=format, + topology_format=topology_format) if not isinstance(topology, Topology) and not topology is None: self.filename = _check_file_like(topology) - topology = _topology_from_file_like( - self.filename, topology_format=topology_format, **kwargs - ) + topology = _topology_from_file_like(self.filename, + topology_format=topology_format, + **kwargs) if topology is not None: self._topology = topology else: # point to Universe.empty instead of making empty universe - raise TypeError( - "Topology argument required to make Universe. " - "Try Universe.empty(n_atoms, ...) to construct " - "your own Universe." - ) + raise TypeError('Topology argument required to make Universe. ' + 'Try Universe.empty(n_atoms, ...) to construct ' + 'your own Universe.') _generate_from_topology(self) # make real atoms, res, segments - coordinates = _resolve_coordinates( - self.filename, *coordinates, format=format, all_coordinates=all_coordinates - ) + coordinates = _resolve_coordinates(self.filename, *coordinates, + format=format, + all_coordinates=all_coordinates) if coordinates: - self.load_new( - coordinates, - format=format, - in_memory=in_memory, - in_memory_step=in_memory_step, - **kwargs, - ) + self.load_new(coordinates, format=format, in_memory=in_memory, + in_memory_step=in_memory_step, **kwargs) if transformations: if callable(transformations): @@ -603,35 +565,30 @@ def __init__( "Universe instantiation. If using guess_TopologyAttrs, " "pass these kwargs to the method instead, as they will override " "the previous Context values.", - DeprecationWarning, + DeprecationWarning ) # Original behaviour is to add additionally guessed bond info # this is achieved by adding to the `to_guess` list (unliked `force_guess` # which replaces existing bonds). - to_guess = list(to_guess) + ["bonds", "angles", "dihedrals"] + to_guess = list(to_guess) + ['bonds', 'angles', 'dihedrals'] + + self.guess_TopologyAttrs( + context, to_guess, force_guess, error_if_missing=False + ) - self.guess_TopologyAttrs(context, to_guess, force_guess, error_if_missing=False) def copy(self): """Return an independent copy of this Universe""" context = self._context.copy() - new = self.__class__(self._topology.copy(), to_guess=(), context=context) + new = self.__class__(self._topology.copy(), + to_guess=(), context=context) new.trajectory = self.trajectory.copy() return new @classmethod - def empty( - cls, - n_atoms, - n_residues=1, - n_segments=1, - n_frames=1, - atom_resindex=None, - residue_segindex=None, - trajectory=False, - velocities=False, - forces=False, - ): + def empty(cls, n_atoms, n_residues=1, n_segments=1, n_frames=1, + atom_resindex=None, residue_segindex=None, + trajectory=False, velocities=False, forces=False): """Create a blank Universe Useful for building a Universe without requiring existing files, @@ -698,24 +655,19 @@ def empty( if atom_resindex is None and n_residues > 1: warnings.warn( - "Residues specified but no atom_resindex given. " - "All atoms will be placed in first Residue.", - UserWarning, - ) + 'Residues specified but no atom_resindex given. ' + 'All atoms will be placed in first Residue.', + UserWarning) if residue_segindex is None and n_segments > 1: warnings.warn( - "Segments specified but no segment_resindex given. " - "All residues will be placed in first Segment", - UserWarning, - ) + 'Segments specified but no segment_resindex given. ' + 'All residues will be placed in first Segment', + UserWarning) - top = Topology( - n_atoms, - n_residues, - n_segments, - atom_resindex=atom_resindex, - residue_segindex=residue_segindex, + top = Topology(n_atoms, n_residues, n_segments, + atom_resindex=atom_resindex, + residue_segindex=residue_segindex, ) u = cls(top, to_guess=()) @@ -727,8 +679,8 @@ def empty( # grab and attach a MemoryReader u.trajectory = get_reader_for(coords)( - coords, order="fac", n_atoms=n_atoms, velocities=vels, forces=forces - ) + coords, order='fac', n_atoms=n_atoms, + velocities=vels, forces=forces) return u @@ -741,9 +693,8 @@ def universe(self): # It is also cleaner than a weakref. return self - def load_new( - self, filename, format=None, in_memory=False, in_memory_step=1, **kwargs - ): + def load_new(self, filename, format=None, in_memory=False, + in_memory_step=1, **kwargs): """Load coordinates from `filename`. The file format of `filename` is autodetected from the file name suffix @@ -816,34 +767,29 @@ def load_new( except ValueError as err: raise TypeError( "Cannot find an appropriate coordinate reader for file '{0}'.\n" - " {1}".format(filename, err) - ) + " {1}".format(filename, err)) # supply number of atoms for readers that cannot do it for themselves - kwargs["n_atoms"] = self.atoms.n_atoms + kwargs['n_atoms'] = self.atoms.n_atoms self.trajectory = reader(filename, format=format, **kwargs) if self.trajectory.n_atoms != len(self.atoms): - raise ValueError( - "The topology and {form} trajectory files don't" - " have the same number of atoms!\n" - "Topology number of atoms {top_n_atoms}\n" - "Trajectory: {fname} Number of atoms {trj_n_atoms}".format( - form=self.trajectory.format, - top_n_atoms=len(self.atoms), - fname=filename, - trj_n_atoms=self.trajectory.n_atoms, - ) - ) + raise ValueError("The topology and {form} trajectory files don't" + " have the same number of atoms!\n" + "Topology number of atoms {top_n_atoms}\n" + "Trajectory: {fname} Number of atoms {trj_n_atoms}".format( + form=self.trajectory.format, + top_n_atoms=len(self.atoms), + fname=filename, + trj_n_atoms=self.trajectory.n_atoms)) if in_memory: self.transfer_to_memory(step=in_memory_step, **kwargs) return self - def transfer_to_memory( - self, start=None, stop=None, step=None, verbose=False, **kwargs - ): + def transfer_to_memory(self, start=None, stop=None, step=None, + verbose=False, **kwargs): """Transfer the trajectory to in memory representation. Replaces the current trajectory reader object with one of type @@ -870,9 +816,9 @@ def transfer_to_memory( from ..coordinates.memory import MemoryReader if not isinstance(self.trajectory, MemoryReader): - n_frames = len( - range(*self.trajectory.check_slice_indices(start, stop, step)) - ) + n_frames = len(range( + *self.trajectory.check_slice_indices(start, stop, step) + )) n_atoms = len(self.atoms) coordinates = np.zeros((n_frames, n_atoms, 3), dtype=np.float32) ts = self.trajectory.ts @@ -882,15 +828,12 @@ def transfer_to_memory( velocities = np.zeros_like(coordinates) if has_vels else None forces = np.zeros_like(coordinates) if has_fors else None - dimensions = np.zeros((n_frames, 6), dtype=np.float32) if has_dims else None + dimensions = (np.zeros((n_frames, 6), dtype=np.float32) + if has_dims else None) - for i, ts in enumerate( - ProgressBar( - self.trajectory[start:stop:step], - verbose=verbose, - desc="Loading frames", - ) - ): + for i, ts in enumerate(ProgressBar(self.trajectory[start:stop:step], + verbose=verbose, + desc="Loading frames")): np.copyto(coordinates[i], ts.positions) if has_vels: np.copyto(velocities[i], ts.velocities) @@ -910,9 +853,7 @@ def transfer_to_memory( dt=self.trajectory.ts.dt * step, filename=self.trajectory.filename, velocities=velocities, - forces=forces, - **kwargs, - ) + forces=forces, **kwargs) # python 2 doesn't allow an efficient splitting of kwargs in function # argument signatures. @@ -964,7 +905,8 @@ def __repr__(self): # n_atoms=len(self.atoms), # bonds=" and {0} bonds".format(len(self.bonds)) if self.bonds else "") - return "".format(n_atoms=len(self.atoms)) + return "".format( + n_atoms=len(self.atoms)) @classmethod def _unpickle_U(cls, top, traj, context): @@ -979,10 +921,8 @@ def __reduce__(self): # __setstate__/__getstate__ will raise an error when Universe has a # transformation (that has AtomGroup inside). Use __reduce__ instead. # Universe's two "legs" of top and traj both serialise themselves. - return ( - self._unpickle_U, - (self._topology, self._trajectory, self._context.copy()), - ) + return (self._unpickle_U, (self._topology, + self._trajectory, self._context.copy())) # Properties @property @@ -1094,16 +1034,16 @@ def add_TopologyAttr(self, topologyattr, values=None): " Possible values: '{}'\n" "To raise an issue go to: " "https://github.com/MDAnalysis/mdanalysis/issues" - "".format(topologyattr, ", ".join(sorted(_TOPOLOGY_ATTRS.keys()))) - ) + "".format( + topologyattr, ', '.join( + sorted(_TOPOLOGY_ATTRS.keys())))) raise ValueError(errmsg) from None else: topologyattr = tcls.from_blank( n_atoms=self._topology.n_atoms, n_residues=self._topology.n_residues, n_segments=self._topology.n_segments, - values=values, - ) + values=values) self._topology.add_TopologyAttr(topologyattr) self._process_attr(topologyattr) @@ -1148,30 +1088,25 @@ def del_TopologyAttr(self, topologyattr): # e.g. matrix -> matrices topologyattr = topologyattr.btype + "s" except AttributeError: - raise ValueError( - "Topology attribute must be str or " - "TopologyAttr object or class. " - f"Given: {type(topologyattr)}" - ) from None + raise ValueError("Topology attribute must be str or " + "TopologyAttr object or class. " + f"Given: {type(topologyattr)}") from None try: topologyattr = _TOPOLOGY_ATTRS[topologyattr].attrname except KeyError: - attrs = ", ".join(sorted(_TOPOLOGY_ATTRS)) - errmsg = ( - f"Unrecognised topology attribute: '{topologyattr}'." - f" Possible values: '{attrs}'\n" - "To raise an issue go to: " - "https://github.com/MDAnalysis/mdanalysis/issues" - ) + attrs = ', '.join(sorted(_TOPOLOGY_ATTRS)) + errmsg = (f"Unrecognised topology attribute: '{topologyattr}'." + f" Possible values: '{attrs}'\n" + "To raise an issue go to: " + "https://github.com/MDAnalysis/mdanalysis/issues") raise ValueError(errmsg) from None try: topattr = getattr(self._topology, topologyattr) except AttributeError: - raise ValueError( - f"Topology attribute {topologyattr} " "not in Universe." - ) from None + raise ValueError(f"Topology attribute {topologyattr} " + "not in Universe.") from None self._topology.del_TopologyAttr(topattr) self._unprocess_attr(topattr) @@ -1183,42 +1118,30 @@ def _process_attr(self, attr): - Component properties - Transplant methods """ - n_dict = { - "atom": self._topology.n_atoms, - "residue": self._topology.n_residues, - "segment": self._topology.n_segments, - } + n_dict = {'atom': self._topology.n_atoms, + 'residue': self._topology.n_residues, + 'segment': self._topology.n_segments} logger.debug("_process_attr: Adding {0} to topology".format(attr)) - if attr.per_object is not None and len(attr) != n_dict[attr.per_object]: - raise ValueError( - "Length of {attr} does not" - " match number of {obj}s.\n" - "Expect: {n:d} Have: {m:d}".format( - attr=attr.attrname, - obj=attr.per_object, - n=n_dict[attr.per_object], - m=len(attr), - ) - ) + if (attr.per_object is not None and len(attr) != n_dict[attr.per_object]): + raise ValueError('Length of {attr} does not' + ' match number of {obj}s.\n' + 'Expect: {n:d} Have: {m:d}'.format( + attr=attr.attrname, + obj=attr.per_object, + n=n_dict[attr.per_object], + m=len(attr))) for cls in attr.target_classes: self._class_bases[cls]._add_prop(attr) # TODO: Try and shove this into cls._add_prop # Group transplants - for cls in ( - Atom, - Residue, - Segment, - GroupBase, - AtomGroup, - ResidueGroup, - SegmentGroup, - ): + for cls in (Atom, Residue, Segment, GroupBase, + AtomGroup, ResidueGroup, SegmentGroup): for funcname, meth in attr.transplants[cls]: setattr(self._class_bases[cls], funcname, meth) # Universe transplants - for funcname, meth in attr.transplants["Universe"]: + for funcname, meth in attr.transplants['Universe']: setattr(self.__class__, funcname, meth) def _unprocess_attr(self, attr): @@ -1318,9 +1241,8 @@ def add_Segment(self, **attrs): # return the new segment return self.segments[segidx] - def _add_topology_objects( - self, object_type, values, types=None, guessed=False, order=None - ): + def _add_topology_objects(self, object_type, values, types=None, guessed=False, + order=None): """Add new TopologyObjects to this Universe Parameters @@ -1355,7 +1277,7 @@ def _add_topology_objects( for x in values: if isinstance(x, (AtomGroup, TopologyObject)): if x.universe is not self: - err_msg = "Cannot add {} from different Universes." + err_msg = 'Cannot add {} from different Universes.' raise ValueError(err_msg.format(object_type)) indices.append(x.indices) else: @@ -1364,8 +1286,8 @@ def _add_topology_objects( all_indices = set([i for obj in indices for i in obj]) nonexistent = all_indices - set(self.atoms.indices) if nonexistent: - istr = ", ".join(map(str, nonexistent)) - err_msg = "Cannot add {} for nonexistent atom indices: {}" + istr = ', '.join(map(str, nonexistent)) + err_msg = 'Cannot add {} for nonexistent atom indices: {}' raise ValueError(err_msg.format(object_type, istr)) try: @@ -1422,23 +1344,22 @@ def add_bonds(self, values, types=None, guessed=False, order=None): .. versionadded:: 1.0.0 """ - self._add_topology_objects( - "bonds", values, types=types, guessed=guessed, order=order - ) + self._add_topology_objects('bonds', values, types=types, + guessed=guessed, order=order) self._invalidate_bond_related_caches() def _invalidate_bond_related_caches(self): """ Invalidate caches related to bonds and fragments. - + This should be called whenever the Universe's bonds are modified. .. versionadded: 2.8.0 """ # Invalidate bond-related caches - self._cache.pop("fragments", None) - self._cache["_valid"].pop("fragments", None) - self._cache["_valid"].pop("fragindices", None) + self._cache.pop('fragments', None) + self._cache['_valid'].pop('fragments', None) + self._cache['_valid'].pop('fragindices', None) def add_angles(self, values, types=None, guessed=False): """Add new Angles to this Universe. @@ -1458,7 +1379,8 @@ def add_angles(self, values, types=None, guessed=False): .. versionadded:: 1.0.0 """ - self._add_topology_objects("angles", values, types=types, guessed=guessed) + self._add_topology_objects('angles', values, types=types, + guessed=guessed) def add_dihedrals(self, values, types=None, guessed=False): """Add new Dihedrals to this Universe. @@ -1479,7 +1401,8 @@ def add_dihedrals(self, values, types=None, guessed=False): .. versionadded:: 1.0.0 """ - self._add_topology_objects("dihedrals", values, types=types, guessed=guessed) + self._add_topology_objects('dihedrals', values, types=types, + guessed=guessed) def add_impropers(self, values, types=None, guessed=False): """Add new Impropers to this Universe. @@ -1500,7 +1423,8 @@ def add_impropers(self, values, types=None, guessed=False): .. versionadded:: 1.0.0 """ - self._add_topology_objects("impropers", values, types=types, guessed=guessed) + self._add_topology_objects('impropers', values, types=types, + guessed=guessed) def _delete_topology_objects(self, object_type, values): """Delete TopologyObjects from this Universe @@ -1521,7 +1445,7 @@ def _delete_topology_objects(self, object_type, values): for x in values: if isinstance(x, (AtomGroup, TopologyObject)): if x.universe is not self: - err_msg = "Cannot delete {} from different Universes." + err_msg = 'Cannot delete {} from different Universes.' raise ValueError(err_msg.format(object_type)) indices.append(x.indices) else: @@ -1530,7 +1454,7 @@ def _delete_topology_objects(self, object_type, values): try: attr = getattr(self._topology, object_type) except AttributeError: - raise ValueError("There are no {} to delete".format(object_type)) + raise ValueError('There are no {} to delete'.format(object_type)) attr._delete_bonds(indices) def delete_bonds(self, values): @@ -1570,7 +1494,7 @@ def delete_bonds(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects("bonds", values) + self._delete_topology_objects('bonds', values) self._invalidate_bond_related_caches() def delete_angles(self, values): @@ -1587,7 +1511,7 @@ def delete_angles(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects("angles", values) + self._delete_topology_objects('angles', values) def delete_dihedrals(self, values): """Delete Dihedrals from this Universe. @@ -1603,7 +1527,7 @@ def delete_dihedrals(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects("dihedrals", values) + self._delete_topology_objects('dihedrals', values) def delete_impropers(self, values): """Delete Impropers from this Universe. @@ -1619,7 +1543,7 @@ def delete_impropers(self, values): .. versionadded:: 1.0.0 """ - self._delete_topology_objects("impropers", values) + self._delete_topology_objects('impropers', values) # TODO: Maybe put this as a Bond attribute transplant # Problems: Can we transplant onto Universe? @@ -1631,7 +1555,7 @@ def delete_impropers(self, values): # Attribute (ie, 2 for the price of 1) # Fragments then gets its own Class/namespace/jazz. @property - @cached("fragments") + @cached('fragments') def _fragdict(self): """ .. versionadded:: 0.9.0 @@ -1652,7 +1576,7 @@ def _fragdict(self): frags = tuple([AtomGroup(np.sort(ix), self) for ix in frag_indices]) fragdict = {} - fraginfo = collections.namedtuple("fraginfo", "ix, fragment") + fraginfo = collections.namedtuple('fraginfo', 'ix, fragment') for i, f in enumerate(frags): for a in f: fragdict[a.ix] = fraginfo(i, f) @@ -1731,38 +1655,29 @@ def from_smiles( except ImportError as e: raise ImportError( "Creating a Universe from a SMILES string requires RDKit but " - "it does not appear to be installed" - ) from e + "it does not appear to be installed") from e mol = Chem.MolFromSmiles(smiles, sanitize=sanitize) if mol is None: - raise SyntaxError("Error while parsing SMILES {0}".format(smiles)) + raise SyntaxError('Error while parsing SMILES {0}'.format(smiles)) if addHs: mol = Chem.AddHs(mol) if generate_coordinates: if not addHs: - raise ValueError( - "Generating coordinates requires adding " - "hydrogens with `addHs=True`" - ) + raise ValueError("Generating coordinates requires adding " + "hydrogens with `addHs=True`") numConfs = rdkit_kwargs.pop("numConfs", numConfs) if not (isinstance(numConfs, int) and numConfs > 0): - raise SyntaxError( - "numConfs must be a non-zero positive " - "integer instead of {0}".format(numConfs) - ) + raise SyntaxError("numConfs must be a non-zero positive " + "integer instead of {0}".format(numConfs)) AllChem.EmbedMultipleConfs(mol, numConfs, **rdkit_kwargs) return cls(mol, **kwargs) def guess_TopologyAttrs( - self, - context=None, - to_guess=None, - force_guess=None, - error_if_missing=True, - **kwargs, + self, context=None, to_guess=None, force_guess=None, + error_if_missing=True, **kwargs ): """ Guess and add attributes through a specific context-aware guesser. @@ -1782,7 +1697,7 @@ def guess_TopologyAttrs( However, starting with release 3.0 **no guessing will be done by default** and it will be up to the user to request guessing using ``to_guess`` and ``force_guess``. - + force_guess: Optional[list[str]] TopologyAttrs in this list will be force guessed. If the TopologyAttr does not already exist in the Universe, this has no @@ -1831,8 +1746,7 @@ def guess_TopologyAttrs( # Set of all Connectivity related attribute names # used to special case attribute replacement after calling the guesser objects = set( - topattr.attrname - for topattr in _TOPOLOGY_ATTRS.values() + topattr.attrname for topattr in _TOPOLOGY_ATTRS.values() if issubclass(topattr, _Connection) ) @@ -1840,25 +1754,25 @@ def guess_TopologyAttrs( # from guesser methods if self._topology.n_atoms > 0: - topology_attrs = [att.attrname for att in self._topology.read_attributes] + topology_attrs = [att.attrname for att in + self._topology.read_attributes] common_attrs = set(to_guess) & set(topology_attrs) common_attrs = ", ".join(attr for attr in common_attrs) if len(common_attrs) > 0: logger.info( - f"The attribute(s) {common_attrs} have already been read " - "from the topology file. The guesser will " - "only guess empty values for this attribute, " - "if any exists. To overwrite it by completely " - "guessed values, you can pass the attribute to" - " the force_guess parameter instead of " - "the to_guess one" - ) + f'The attribute(s) {common_attrs} have already been read ' + 'from the topology file. The guesser will ' + 'only guess empty values for this attribute, ' + 'if any exists. To overwrite it by completely ' + 'guessed values, you can pass the attribute to' + ' the force_guess parameter instead of ' + 'the to_guess one') for attr in total_guess: if guesser.is_guessable(attr): - fg = attr in force_guess + fg = attr in force_guess try: values = guesser.guess_attr(attr, fg) except NoDataError as e: @@ -1877,22 +1791,24 @@ def guess_TopologyAttrs( group = getattr(self.atoms, attr) self._delete_topology_objects(attr, group) # this method appends any new bonds in values to existing bonds - self._add_topology_objects(attr, values, guessed=True) + self._add_topology_objects( + attr, values, guessed=True) if attr == "bonds": self._invalidate_bond_related_caches() else: guessed_attr = _TOPOLOGY_ATTRS[attr](values, True) self.add_TopologyAttr(guessed_attr) - logger.info(f"attribute {attr} has been guessed" " successfully.") + logger.info( + f'attribute {attr} has been guessed' + ' successfully.') else: - raise ValueError( - f"{context} guesser can not guess the" - f" following attribute: {attr}" - ) + raise ValueError(f'{context} guesser can not guess the' + f' following attribute: {attr}') else: - warnings.warn("Can not guess attributes " "for universe with 0 atoms") + warnings.warn('Can not guess attributes ' + 'for universe with 0 atoms') def set_groups(self, atomwise_resids=None, atomwise_segids=None): """Set the groups (`ResidueGroup`, `SegmentGroup`) of the Universe @@ -1948,10 +1864,8 @@ def set_groups(self, atomwise_resids=None, atomwise_segids=None): .. versionadded:: 2.10.0 """ if (atomwise_resids is None) and (atomwise_segids is None): - warnings.warn( - "Not setting groups. Please provide atomwise_resids or " - "atomwise_segids." - ) + warnings.warn("Not setting groups. Please provide atomwise_resids or " + "atomwise_segids.") return # resids @@ -1963,15 +1877,12 @@ def set_groups(self, atomwise_resids=None, atomwise_segids=None): if len(atomwise_resids) != self.atoms.n_atoms: raise ValueError( "The length of atomwise_resids should be the same as " - "the number of atoms in the universe." - ) + "the number of atoms in the universe.") self.atomwise_resids_orig = self.atoms.resids - logger.info( - "The new resids replaces the current one. " - "The original resids is stored in " - "atomwise_resids_orig." - ) + logger.info("The new resids replaces the current one. " + "The original resids is stored in " + "atomwise_resids_orig.") # segids if atomwise_segids is None: @@ -1982,22 +1893,19 @@ def set_groups(self, atomwise_resids=None, atomwise_segids=None): if len(atomwise_segids) != self.atoms.n_atoms: raise ValueError( "The length of atomwise_segids should be the same as " - "the number of atoms in the universe." - ) + "the number of atoms in the universe.") self.atomwise_segids_orig = self.atoms.segids - logger.info( - "The new resids replaces the current one. " - "The original segids is stored in " - "atomwise_segids_orig." - ) + logger.info("The new resids replaces the current one. " + "The original segids is stored in " + "atomwise_segids_orig.") atomwise_resids = np.array(atomwise_resids, dtype=int) atomwise_segids = np.array(atomwise_segids, dtype=object) - _update_topology_by_ids( - self, atomwise_resids=atomwise_resids, atomwise_segids=atomwise_segids - ) + _update_topology_by_ids(self, + atomwise_resids=atomwise_resids, + atomwise_segids=atomwise_segids) _generate_from_topology(self) @@ -2081,8 +1989,9 @@ def Merge(*args): # Create a new topology using the intersection of topology attributes blank_topology_attrs = set(dir(Topology(attrs=[]))) - common_attrs = set.intersection(*[set(dir(ag.universe._topology)) for ag in args]) - tops = set(["bonds", "angles", "dihedrals", "impropers"]) + common_attrs = set.intersection(*[set(dir(ag.universe._topology)) + for ag in args]) + tops = set(['bonds', 'angles', 'dihedrals', 'impropers']) attrs = [] @@ -2102,17 +2011,13 @@ def Merge(*args): elif issubclass(attr_class, SegmentAttr): attr = getattr(ag.segments, attrname) else: - raise NotImplementedError( - "Don't know how to handle" - " TopologyAttr not subclassed" - " from AtomAttr, ResidueAttr," - " or SegmentAttr." - ) + raise NotImplementedError("Don't know how to handle" + " TopologyAttr not subclassed" + " from AtomAttr, ResidueAttr," + " or SegmentAttr.") if type(attr) != np.ndarray: - raise TypeError( - "Encountered unexpected topology " - "attribute of type {}".format(type(attr)) - ) + raise TypeError('Encountered unexpected topology ' + 'attribute of type {}'.format(type(attr))) try: attr_array.extend(attr) except NameError: @@ -2122,7 +2027,7 @@ def Merge(*args): # Build up topology groups including only those that all arguments' # universes have - for t in tops & common_attrs: + for t in (tops & common_attrs): offset = 0 bondidx = [] types = [] @@ -2140,14 +2045,14 @@ def Merge(*args): # Map them so they refer to our new indices new_idx = [tuple([mapping[x] for x in entry]) for entry in tg.indices] bondidx.extend(new_idx) - if hasattr(tg, "_bondtypes"): + if hasattr(tg, '_bondtypes'): types.extend(tg._bondtypes) else: - types.extend([None] * len(tg)) + types.extend([None]*len(tg)) if any(t is None for t in types): attrs.append(bonds_class(bondidx)) else: - types = np.array(types, dtype="|S8") + types = np.array(types, dtype='|S8') attrs.append(bonds_class(bondidx, types)) # Renumber residue and segment indices @@ -2158,12 +2063,10 @@ def Merge(*args): seg_offset = 0 for ag in args: # create a mapping scheme for this atomgroup's parents - res_mapping = { - r.resindex: i for i, r in enumerate(ag.residues, start=res_offset) - } - seg_mapping = { - r.segindex: i for i, r in enumerate(ag.segments, start=seg_offset) - } + res_mapping = {r.resindex: i for i, r in enumerate(ag.residues, + start=res_offset)} + seg_mapping = {r.segindex: i for i, r in enumerate(ag.segments, + start=seg_offset)} res_offset += len(ag.residues) seg_offset += len(ag.segments) @@ -2179,24 +2082,19 @@ def Merge(*args): n_residues = len(set(residx)) n_segments = len(set(segidx)) - top = Topology( - n_atoms, - n_residues, - n_segments, - attrs=attrs, - atom_resindex=residx, - residue_segindex=segidx, - ) + top = Topology(n_atoms, n_residues, n_segments, + attrs=attrs, + atom_resindex=residx, + residue_segindex=segidx) # Create and populate a universe try: - # Create universe with coordinates if they exists in args + #Create universe with coordinates if they exists in args coords = np.vstack([a.positions for a in args]) - u = Universe( - top, coords[None, :, :], format=MDAnalysis.coordinates.memory.MemoryReader - ) + u = Universe(top, coords[None, :, :], + format=MDAnalysis.coordinates.memory.MemoryReader) except AttributeError: - # Create universe without coordinates if they dont exists in args + #Create universe without coordinates if they dont exists in args u = Universe(top) return u diff --git a/package/MDAnalysis/due.py b/package/MDAnalysis/due.py index 4d6f52e7d5..7ab1e8b55a 100644 --- a/package/MDAnalysis/due.py +++ b/package/MDAnalysis/due.py @@ -65,7 +65,9 @@ def _donothing_func(*args, **kwargs): from duecredit import due, BibTeX, Doi, Url if "due" in locals() and not hasattr(due, "cite"): - raise RuntimeError("Imported due lacks .cite. DueCredit is now disabled") + raise RuntimeError( + "Imported due lacks .cite. DueCredit is now disabled" + ) except Exception as err: if not isinstance(err, ImportError): import logging diff --git a/package/MDAnalysis/guesser/base.py b/package/MDAnalysis/guesser/base.py index bfd7168b4a..c7bcc21e82 100644 --- a/package/MDAnalysis/guesser/base.py +++ b/package/MDAnalysis/guesser/base.py @@ -142,7 +142,8 @@ def guess_attr(self, attr_to_guess, force_guess=False): top_attr = _TOPOLOGY_ATTRS[attr_to_guess] except KeyError: raise KeyError( - f"{attr_to_guess} is not a recognized MDAnalysis " "topology attribute" + f"{attr_to_guess} is not a recognized MDAnalysis " + "topology attribute" ) # make attribute to guess plural attr_to_guess = top_attr.attrname @@ -163,7 +164,9 @@ def guess_attr(self, attr_to_guess, force_guess=False): # check if the topology already has the attribute to partially guess it if hasattr(self._universe.atoms, attr_to_guess) and not force_guess: - attr_values = np.array(getattr(self._universe.atoms, attr_to_guess, None)) + attr_values = np.array( + getattr(self._universe.atoms, attr_to_guess, None) + ) empty_values = top_attr.are_values_missing(attr_values) diff --git a/package/MDAnalysis/guesser/default_guesser.py b/package/MDAnalysis/guesser/default_guesser.py index a0deeb0245..2ecc64c1e6 100644 --- a/package/MDAnalysis/guesser/default_guesser.py +++ b/package/MDAnalysis/guesser/default_guesser.py @@ -438,7 +438,9 @@ def guess_bonds(self, atoms=None, coords=None): raise ValueError( ( "vdw radii for types: " - + ", ".join([t for t in set(atomtypes) if t not in vdwradii]) + + ", ".join( + [t for t in set(atomtypes) if t not in vdwradii] + ) + ". These can be defined manually using the" + f" keyword 'vdwradii'" ) @@ -462,7 +464,9 @@ def guess_bonds(self, atoms=None, coords=None): coords, max_cutoff=2.0 * max_vdw, min_cutoff=lower_bound, box=box ) for idx, (i, j) in enumerate(pairs): - d = (vdwradii[atomtypes[i]] + vdwradii[atomtypes[j]]) * fudge_factor + d = ( + vdwradii[atomtypes[i]] + vdwradii[atomtypes[j]] + ) * fudge_factor if dist[idx] < d: bonds.append((atoms[i].index, atoms[j].index)) return tuple(bonds) @@ -512,7 +516,9 @@ def guess_angles(self, bonds=None): for other_b in atom.bonds: if other_b != b: # if not the same bond I start as third_a = other_b.partner(atom) - desc = tuple([other_a.index, atom.index, third_a.index]) + desc = tuple( + [other_a.index, atom.index, third_a.index] + ) # first index always less than last if desc[0] > desc[-1]: desc = desc[::-1] @@ -563,7 +569,9 @@ def guess_dihedrals(self, angles=None): a_tup = tuple([a.index for a in b]) # angle as tuple of numbers # if searching with b[0], want tuple of (b[2], b[1], b[0], +new) # search the first and last atom of each angle - for atom, prefix in zip([b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup]): + for atom, prefix in zip( + [b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup] + ): for other_b in atom.bonds: if not other_b.partner(atom) in b: third_a = other_b.partner(atom) @@ -671,6 +679,9 @@ def guess_gasteiger_charges(self, atomgroup): ComputeGasteigerCharges(mol, throwOnParamFailure=True) return np.array( - [atom.GetDoubleProp("_GasteigerCharge") for atom in mol.GetAtoms()], + [ + atom.GetDoubleProp("_GasteigerCharge") + for atom in mol.GetAtoms() + ], dtype=np.float32, ) diff --git a/package/MDAnalysis/lib/NeighborSearch.py b/package/MDAnalysis/lib/NeighborSearch.py index d8b6d60d90..b1f5fa7185 100644 --- a/package/MDAnalysis/lib/NeighborSearch.py +++ b/package/MDAnalysis/lib/NeighborSearch.py @@ -136,4 +136,6 @@ def _index2level( elif level == "S": return atomgroup.segments else: - raise NotImplementedError("{0}: level not implemented".format(level)) + raise NotImplementedError( + "{0}: level not implemented".format(level) + ) diff --git a/package/MDAnalysis/lib/_distopia.py b/package/MDAnalysis/lib/_distopia.py index 20b814e099..a6ec059168 100644 --- a/package/MDAnalysis/lib/_distopia.py +++ b/package/MDAnalysis/lib/_distopia.py @@ -121,7 +121,9 @@ def calc_dihedral( coords4: np.ndarray, results: np.ndarray, ) -> None: - distopia.dihedrals_no_box(coords1, coords2, coords3, coords4, results=results) + distopia.dihedrals_no_box( + coords1, coords2, coords3, coords4, results=results + ) def calc_dihedral_ortho( diff --git a/package/MDAnalysis/lib/distances.py b/package/MDAnalysis/lib/distances.py index 5084d53464..b3f862e005 100644 --- a/package/MDAnalysis/lib/distances.py +++ b/package/MDAnalysis/lib/distances.py @@ -161,7 +161,9 @@ import importlib _distances = {} -_distances["serial"] = importlib.import_module(".c_distances", package="MDAnalysis.lib") +_distances["serial"] = importlib.import_module( + ".c_distances", package="MDAnalysis.lib" +) try: _distances["openmp"] = importlib.import_module( ".c_distances_openmp", package="MDAnalysis.lib" @@ -224,7 +226,9 @@ def _run( from .c_distances_openmp import OPENMP_ENABLED as USED_OPENMP -def _check_result_array(result: Optional[npt.NDArray], shape: tuple) -> npt.NDArray: +def _check_result_array( + result: Optional[npt.NDArray], shape: tuple +) -> npt.NDArray: """Check if the result array is ok to use. The `result` array must meet the following requirements: @@ -708,8 +712,12 @@ def _determine_method( return methods["nsgrid"] else: if box is None: - min_dim = np.array([reference.min(axis=0), configuration.min(axis=0)]) - max_dim = np.array([reference.max(axis=0), configuration.max(axis=0)]) + min_dim = np.array( + [reference.min(axis=0), configuration.min(axis=0)] + ) + max_dim = np.array( + [reference.max(axis=0), configuration.max(axis=0)] + ) size = max_dim.max(axis=0) - min_dim.min(axis=0) elif np.all(box[3:] == 90.0): size = box[:3] @@ -806,9 +814,13 @@ def _bruteforce_capped( distances = np.empty((0,), dtype=np.float64) if len(reference) > 0 and len(configuration) > 0: - _distances = distance_array(reference, configuration, box=box, backend=backend) + _distances = distance_array( + reference, configuration, box=box, backend=backend + ) if min_cutoff is not None: - mask = np.where((_distances <= max_cutoff) & (_distances > min_cutoff)) + mask = np.where( + (_distances <= max_cutoff) & (_distances > min_cutoff) + ) else: mask = np.where((_distances <= max_cutoff)) if mask[0].size > 0: @@ -1032,7 +1044,9 @@ def _nsgrid_capped( # Extra padding near the origin shiftref -= lmin - 0.1 * max_cutoff shiftconf -= lmin - 0.1 * max_cutoff - gridsearch = FastNS(max_cutoff, shiftconf, box=pseudobox, pbc=False) + gridsearch = FastNS( + max_cutoff, shiftconf, box=pseudobox, pbc=False + ) results = gridsearch.search(shiftref) else: gridsearch = FastNS(max_cutoff, configuration, box=box) diff --git a/package/MDAnalysis/lib/mdamath.py b/package/MDAnalysis/lib/mdamath.py index 7e55becb50..cef449c8f2 100644 --- a/package/MDAnalysis/lib/mdamath.py +++ b/package/MDAnalysis/lib/mdamath.py @@ -163,7 +163,9 @@ def angle(a: npt.ArrayLike, b: npt.ArrayLike) -> float: return np.arccos(x) -def stp(vec1: npt.ArrayLike, vec2: npt.ArrayLike, vec3: npt.ArrayLike) -> float: +def stp( + vec1: npt.ArrayLike, vec2: npt.ArrayLike, vec3: npt.ArrayLike +) -> float: r"""Takes the scalar triple product of three vectors. Returns the volume *V* of the parallel epiped spanned by the three @@ -249,7 +251,9 @@ def sarrus_det(matrix: npt.NDArray) -> Union[float, npt.NDArray]: return _sarrus_det_multiple(m.reshape((-1, 3, 3))).reshape(shape[:-2]) -def triclinic_box(x: npt.ArrayLike, y: npt.ArrayLike, z: npt.ArrayLike) -> npt.NDArray: +def triclinic_box( + x: npt.ArrayLike, y: npt.ArrayLike, z: npt.ArrayLike +) -> npt.NDArray: """Convert the three triclinic box vectors to ``[lx, ly, lz, alpha, beta, gamma]``. @@ -364,7 +368,9 @@ def triclinic_vectors( dim = np.asarray(dimensions, dtype=np.float64) lx, ly, lz, alpha, beta, gamma = dim # Only positive edge lengths and angles in (0, 180) are allowed: - if not (np.all(dim > 0.0) and alpha < 180.0 and beta < 180.0 and gamma < 180.0): + if not ( + np.all(dim > 0.0) and alpha < 180.0 and beta < 180.0 and gamma < 180.0 + ): # invalid box, return zero vectors: box_matrix = np.zeros((3, 3), dtype=dtype) # detect orthogonal boxes: diff --git a/package/MDAnalysis/lib/picklable_file_io.py b/package/MDAnalysis/lib/picklable_file_io.py index b86e4de03d..f8050b14e5 100644 --- a/package/MDAnalysis/lib/picklable_file_io.py +++ b/package/MDAnalysis/lib/picklable_file_io.py @@ -460,7 +460,9 @@ def pickle_open(name, mode="rt"): .. versionadded:: 2.0.0 """ if mode not in {"r", "rt", "rb"}: - raise ValueError("Only read mode ('r', 'rt', 'rb') " "files can be pickled.") + raise ValueError( + "Only read mode ('r', 'rt', 'rb') " "files can be pickled." + ) name = os.fspath(name) raw = FileIOPicklable(name) if mode == "rb": @@ -531,7 +533,9 @@ def bz2_pickle_open(name, mode="rb"): .. versionadded:: 2.0.0 """ if mode not in {"r", "rt", "rb"}: - raise ValueError("Only read mode ('r', 'rt', 'rb') " "files can be pickled.") + raise ValueError( + "Only read mode ('r', 'rt', 'rb') " "files can be pickled." + ) bz_mode = mode.replace("t", "") binary_file = BZ2Picklable(name, bz_mode) if "t" in mode: @@ -602,7 +606,9 @@ def gzip_pickle_open(name, mode="rb"): .. versionadded:: 2.0.0 """ if mode not in {"r", "rt", "rb"}: - raise ValueError("Only read mode ('r', 'rt', 'rb') " "files can be pickled.") + raise ValueError( + "Only read mode ('r', 'rt', 'rb') " "files can be pickled." + ) gz_mode = mode.replace("t", "") binary_file = GzipPicklable(name, gz_mode) if "t" in mode: diff --git a/package/MDAnalysis/lib/pkdtree.py b/package/MDAnalysis/lib/pkdtree.py index b125a7a478..952b4672e3 100644 --- a/package/MDAnalysis/lib/pkdtree.py +++ b/package/MDAnalysis/lib/pkdtree.py @@ -62,7 +62,9 @@ class PeriodicKDTree(object): """ - def __init__(self, box: Optional[npt.ArrayLike] = None, leafsize: int = 10) -> None: + def __init__( + self, box: Optional[npt.ArrayLike] = None, leafsize: int = 10 + ) -> None: """ Parameters @@ -96,7 +98,9 @@ def pbc(self): """ return self.box is not None - def set_coords(self, coords: npt.ArrayLike, cutoff: Optional[float] = None) -> None: + def set_coords( + self, coords: npt.ArrayLike, cutoff: Optional[float] = None + ) -> None: """Constructs KDTree from the coordinates Wrapping of coordinates to the primary unit cell is enforced @@ -143,7 +147,9 @@ def set_coords(self, coords: npt.ArrayLike, cutoff: Optional[float] = None) -> N # Bring the coordinates in the central cell self.coords = apply_PBC(coords, self.box) # generate duplicate images - self.aug, self.mapping = augment_coordinates(self.coords, self.box, cutoff) + self.aug, self.mapping = augment_coordinates( + self.coords, self.box, cutoff + ) # Images + coords self.all_coords = np.concatenate([self.coords, self.aug]) self.ckdt = cKDTree(self.all_coords, leafsize=self.leafsize) @@ -151,7 +157,8 @@ def set_coords(self, coords: npt.ArrayLike, cutoff: Optional[float] = None) -> N # if cutoff distance is provided for non PBC calculations if cutoff is not None: raise RuntimeError( - "Donot provide cutoff distance for" " non PBC aware calculations" + "Donot provide cutoff distance for" + " non PBC aware calculations" ) self.coords = coords self.ckdt = cKDTree(self.coords, self.leafsize) @@ -182,9 +189,13 @@ def search(self, centers: npt.ArrayLike, radius: float) -> npt.NDArray: # Sanity check if self.pbc: if self.cutoff is None: - raise ValueError("Cutoff needs to be provided when working with PBC.") + raise ValueError( + "Cutoff needs to be provided when working with PBC." + ) if self.cutoff < radius: - raise RuntimeError("Set cutoff greater or equal to the radius.") + raise RuntimeError( + "Set cutoff greater or equal to the radius." + ) # Bring all query points to the central cell wrapped_centers = apply_PBC(centers, self.box) indices = list(self.ckdt.query_ball_point(wrapped_centers, radius)) @@ -232,15 +243,23 @@ def search_pairs(self, radius: float) -> npt.NDArray: if self.pbc: if self.cutoff is None: - raise ValueError("Cutoff needs to be provided when working with PBC.") + raise ValueError( + "Cutoff needs to be provided when working with PBC." + ) if self.cutoff < radius: - raise RuntimeError("Set cutoff greater or equal to the radius.") + raise RuntimeError( + "Set cutoff greater or equal to the radius." + ) pairs = np.array(list(self.ckdt.query_pairs(radius)), dtype=np.intp) if self.pbc: if len(pairs) > 1: - pairs[:, 0] = undo_augment(pairs[:, 0], self.mapping, len(self.coords)) - pairs[:, 1] = undo_augment(pairs[:, 1], self.mapping, len(self.coords)) + pairs[:, 0] = undo_augment( + pairs[:, 0], self.mapping, len(self.coords) + ) + pairs[:, 1] = undo_augment( + pairs[:, 1], self.mapping, len(self.coords) + ) if pairs.size > 0: # First sort the pairs then pick the unique pairs pairs = np.sort(pairs, axis=1) @@ -288,9 +307,13 @@ class initialization # Sanity check if self.pbc: if self.cutoff is None: - raise ValueError("Cutoff needs to be provided when working with PBC.") + raise ValueError( + "Cutoff needs to be provided when working with PBC." + ) if self.cutoff < radius: - raise RuntimeError("Set cutoff greater or equal to the radius.") + raise RuntimeError( + "Set cutoff greater or equal to the radius." + ) # Bring all query points to the central cell wrapped_centers = apply_PBC(centers, self.box) other_tree = cKDTree(wrapped_centers, leafsize=self.leafsize) @@ -300,7 +323,9 @@ class initialization dtype=np.intp, ) if pairs.size > 0: - pairs[:, 1] = undo_augment(pairs[:, 1], self.mapping, len(self.coords)) + pairs[:, 1] = undo_augment( + pairs[:, 1], self.mapping, len(self.coords) + ) else: other_tree = cKDTree(centers, leafsize=self.leafsize) pairs = other_tree.query_ball_tree(self.ckdt, radius) diff --git a/package/MDAnalysis/lib/transformations.py b/package/MDAnalysis/lib/transformations.py index 627f09db76..27e5f01db9 100644 --- a/package/MDAnalysis/lib/transformations.py +++ b/package/MDAnalysis/lib/transformations.py @@ -377,11 +377,17 @@ def rotation_from_matrix(matrix): # rotation angle depending on direction cosa = (np.trace(R33) - 1.0) / 2.0 if abs(direction[2]) > 1e-8: - sina = (R[1, 0] + (cosa - 1.0) * direction[0] * direction[1]) / direction[2] + sina = ( + R[1, 0] + (cosa - 1.0) * direction[0] * direction[1] + ) / direction[2] elif abs(direction[1]) > 1e-8: - sina = (R[0, 2] + (cosa - 1.0) * direction[0] * direction[2]) / direction[1] + sina = ( + R[0, 2] + (cosa - 1.0) * direction[0] * direction[2] + ) / direction[1] else: - sina = (R[2, 1] + (cosa - 1.0) * direction[1] * direction[2]) / direction[0] + sina = ( + R[2, 1] + (cosa - 1.0) * direction[1] * direction[2] + ) / direction[0] angle = math.atan2(sina, cosa) return angle, direction, point @@ -476,7 +482,9 @@ def scale_from_matrix(matrix): return factor, origin, direction -def projection_matrix(point, normal, direction=None, perspective=None, pseudo=False): +def projection_matrix( + point, normal, direction=None, perspective=None, pseudo=False +): """Return matrix to project onto plane defined by point and normal. Using either perspective point, projection direction, or none of both. @@ -528,7 +536,9 @@ def projection_matrix(point, normal, direction=None, perspective=None, pseudo=Fa M[3, 3] = np.dot(perspective, normal) elif direction is not None: # parallel projection - direction = np.array(direction[:3], dtype=np.float64, copy=no_copy_shim) + direction = np.array( + direction[:3], dtype=np.float64, copy=no_copy_shim + ) scale = np.dot(direction, normal) M[:3, :3] -= np.outer(direction, normal) / scale M[:3, 3] = direction * (np.dot(point, normal) / scale) @@ -604,7 +614,9 @@ def projection_from_matrix(matrix, pseudo=False): # perspective projection i = np.where(abs(np.real(l)) > 1e-8)[0] if not len(i): - raise ValueError("no eigenvector not corresponding to eigenvalue 0") + raise ValueError( + "no eigenvector not corresponding to eigenvalue 0" + ) point = np.real(V[:, i[-1]]).squeeze() point /= point[3] normal = -M[3, :3] @@ -730,7 +742,9 @@ def shear_from_matrix(matrix): l, V = np.linalg.eig(M33) i = np.where(abs(np.real(l) - 1.0) < 1e-4)[0] if len(i) < 2: - raise ValueError("no two linear independent eigenvectors found {0!s}".format(l)) + raise ValueError( + "no two linear independent eigenvectors found {0!s}".format(l) + ) V = np.real(V[:, i]).squeeze().T lenorm = -1.0 for i0, i1 in ((0, 1), (0, 2), (1, 2)): diff --git a/package/MDAnalysis/lib/util.py b/package/MDAnalysis/lib/util.py index 3148def31b..d227763d9e 100644 --- a/package/MDAnalysis/lib/util.py +++ b/package/MDAnalysis/lib/util.py @@ -411,10 +411,14 @@ def anyopen(datasource, mode="rt", reset=True): if stream is None: raise IOError( errno.EIO, - "Cannot open file or stream in mode={mode!r}.".format(**vars()), + "Cannot open file or stream in mode={mode!r}.".format( + **vars() + ), repr(filename), ) - elif mode.startswith("w") or mode.startswith("a"): # append 'a' not tested... + elif mode.startswith("w") or mode.startswith( + "a" + ): # append 'a' not tested... if isstream(datasource): stream = datasource try: @@ -434,7 +438,9 @@ def anyopen(datasource, mode="rt", reset=True): if stream is None: raise IOError( errno.EIO, - "Cannot open file or stream in mode={mode!r}.".format(**vars()), + "Cannot open file or stream in mode={mode!r}.".format( + **vars() + ), repr(filename), ) else: @@ -699,7 +705,9 @@ def __init__(self, stream, filename, reset=True, close=False): # on __del__ and super on python 3. Let's warn the user and ensure the # class works normally. if isinstance(stream, NamedStream): - warnings.warn("Constructed NamedStream from a NamedStream", RuntimeWarning) + warnings.warn( + "Constructed NamedStream from a NamedStream", RuntimeWarning + ) stream = stream.stream self.stream = stream self.name = filename @@ -951,7 +959,9 @@ def realpath(*args): """ if None in args: return None - return os.path.realpath(os.path.expanduser(os.path.expandvars(os.path.join(*args)))) + return os.path.realpath( + os.path.expanduser(os.path.expandvars(os.path.join(*args))) + ) def get_ext(filename): @@ -1169,7 +1179,10 @@ def read(self, line): try: return self.convertor(line[self.start : self.stop]) except ValueError: - errmsg = f"{self}: Failed to read&convert " f"{line[self.start:self.stop]}" + errmsg = ( + f"{self}: Failed to read&convert " + f"{line[self.start:self.stop]}" + ) raise ValueError(errmsg) from None def __len__(self): @@ -1220,14 +1233,18 @@ def __init__(self, fmt): """ self.fmt = fmt.split(",") - descriptors = [self.parse_FORTRAN_format(descriptor) for descriptor in self.fmt] + descriptors = [ + self.parse_FORTRAN_format(descriptor) for descriptor in self.fmt + ] start = 0 self.entries = [] for d in descriptors: if d["format"] != "X": for x in range(d["repeat"]): stop = start + d["length"] - self.entries.append(FixedcolumnEntry(start, stop, d["format"])) + self.entries.append( + FixedcolumnEntry(start, stop, d["format"]) + ) start = stop else: start += d["totallength"] @@ -1298,7 +1315,9 @@ def parse_FORTRAN_format(self, edit_descriptor): m = _FORTRAN_format_pattern.match(edit_descriptor.upper()) if m is None: try: - m = _FORTRAN_format_pattern.match("1" + edit_descriptor.upper()) + m = _FORTRAN_format_pattern.match( + "1" + edit_descriptor.upper() + ) if m is None: raise ValueError # really no idea what the descriptor is supposed to mean except: @@ -1461,7 +1480,9 @@ def get_weights(atoms, weights): } #: translation table for 1-letter codes --> *canonical* 3-letter codes. #: The table is used for :func:`convert_aa_code`. -amino_acid_codes = {one: three for three, one in canonical_inverse_aa_codes.items()} +amino_acid_codes = { + one: three for three, one in canonical_inverse_aa_codes.items() +} #: non-default charge state amino acids or special charge state descriptions #: (Not fully synchronized with :class:`MDAnalysis.core.selection.ProteinSelection`.) # fmt: off @@ -1736,7 +1757,9 @@ def unique_rows(arr, return_index=False): ) return u.view(arr.dtype).reshape(-1, m), r_idx else: - u = np.unique(arr.view(dtype=np.dtype([(str(i), arr.dtype) for i in range(m)]))) + u = np.unique( + arr.view(dtype=np.dtype([(str(i), arr.dtype) for i in range(m)])) + ) return u.view(arr.dtype).reshape(-1, m) @@ -2003,7 +2026,9 @@ def wrapper(group, *args, **kwargs): if group.isunique or warn_if_not_unique.warned: return groupmethod(group, *args, **kwargs) # Otherwise, throw a DuplicateWarning and execute the method. - method_name = ".".join((group.__class__.__name__, groupmethod.__name__)) + method_name = ".".join( + (group.__class__.__name__, groupmethod.__name__) + ) # Try to get the group's variable name(s): caller_locals = inspect.currentframe().f_back.f_locals.items() group_names = [] @@ -2020,8 +2045,9 @@ def wrapper(group, *args, **kwargs): else: group_name = " a.k.a. ".join(sorted(group_names)) group_repr = repr(group) - msg = "{}(): {} {} contains duplicates. Results might be biased!" "".format( - method_name, group_name, group_repr + msg = ( + "{}(): {} {} contains duplicates. Results might be biased!" + "".format(method_name, group_name, group_repr) ) warnings.warn(message=msg, category=DuplicateWarning, stacklevel=2) warn_if_not_unique.warned = True @@ -2157,11 +2183,14 @@ def check_coords(*coord_names, **options): allow_single = options.get("allow_single", True) convert_single = options.get("convert_single", True) reduce_result_if_single = options.get("reduce_result_if_single", True) - check_lengths_match = options.get("check_lengths_match", len(coord_names) > 1) + check_lengths_match = options.get( + "check_lengths_match", len(coord_names) > 1 + ) allow_atomgroup = options.get("allow_atomgroup", False) if not coord_names: raise ValueError( - "Decorator check_coords() cannot be used without " "positional arguments." + "Decorator check_coords() cannot be used without " + "positional arguments." ) def check_coords_decorator(func): @@ -2207,7 +2236,9 @@ def _check_coords(coords, argname): raise ValueError(errmsg) if enforce_dtype: try: - coords = coords.astype(np.float32, order="C", copy=enforce_copy) + coords = coords.astype( + np.float32, order="C", copy=enforce_copy + ) except ValueError: errmsg = ( f"{fname}(): {argname}.dtype must be" @@ -2267,11 +2298,15 @@ def wrapper(*args, **kwargs): for name in coord_names: idx = posargnames.index(name) if idx < len(args): - args[idx], is_single, ncoord = _check_coords(args[idx], name) + args[idx], is_single, ncoord = _check_coords( + args[idx], name + ) all_single &= is_single ncoords.append(ncoord) else: - kwargs[name], is_single, ncoord = _check_coords(kwargs[name], name) + kwargs[name], is_single, ncoord = _check_coords( + kwargs[name], name + ) all_single &= is_single ncoords.append(ncoord) if check_lengths_match and ncoords: @@ -2359,7 +2394,8 @@ def __init__( self.new_name = new_name if release is None: raise ValueError( - "deprecate: provide release in which " "feature was deprecated." + "deprecate: provide release in which " + "feature was deprecated." ) self.release = str(release) self.remove = str(remove) if remove is not None else remove diff --git a/package/MDAnalysis/selections/base.py b/package/MDAnalysis/selections/base.py index 4b1db414b1..d9b49e516d 100644 --- a/package/MDAnalysis/selections/base.py +++ b/package/MDAnalysis/selections/base.py @@ -108,7 +108,9 @@ class SelectionWriterBase(metaclass=_Selectionmeta): commentfmt = None default_numterms = 8 - def __init__(self, filename, mode="w", numterms=None, preamble=None, **kwargs): + def __init__( + self, filename, mode="w", numterms=None, preamble=None, **kwargs + ): """Set up for writing to *filename*. Parameters @@ -128,7 +130,9 @@ def __init__(self, filename, mode="w", numterms=None, preamble=None, **kwargs): """ self.filename = util.filename(filename, ext=self.ext) if not mode in ("a", "w"): - raise ValueError("mode must be one of 'w', 'a', not {0!r}".format(mode)) + raise ValueError( + "mode must be one of 'w', 'a', not {0!r}".format(mode) + ) self.mode = mode self._current_mode = mode[0] if numterms is None or numterms < 0: @@ -208,7 +212,9 @@ def write(self, selection, number=None, name=None, frame=None, mode=None): out.write(" ".join(line)) if len(line) == step and not iatom + step == len(selection.atoms): out.write(" " + self.continuation + "\n") - out.write(" ") # safe so that we don't have to put a space at the start of tail + out.write( + " " + ) # safe so that we don't have to put a space at the start of tail self._write_tail(out) out.write("\n") # always terminate with newline diff --git a/package/MDAnalysis/selections/charmm.py b/package/MDAnalysis/selections/charmm.py index c481f9afb0..62bbbd0497 100644 --- a/package/MDAnalysis/selections/charmm.py +++ b/package/MDAnalysis/selections/charmm.py @@ -47,7 +47,9 @@ class SelectionWriter(base.SelectionWriterBase): ext = "str" continuation = "-" commentfmt = "! %s" - default_numterms = 4 # be conservative because CHARMM only reads 72 columns + default_numterms = ( + 4 # be conservative because CHARMM only reads 72 columns + ) def _translate(self, atoms, **kwargs): # CHARMM index is 1-based @@ -58,7 +60,11 @@ def _index(atom): def _write_head(self, out, **kwargs): out.write(self.comment("MDAnalysis CHARMM selection")) - out.write("DEFINE {name!s} SELECT ".format(**kwargs) + self.continuation + "\n") + out.write( + "DEFINE {name!s} SELECT ".format(**kwargs) + + self.continuation + + "\n" + ) def _write_tail(self, out, **kwargs): out.write("END") diff --git a/package/MDAnalysis/selections/pymol.py b/package/MDAnalysis/selections/pymol.py index f61171c2fb..d528a1394b 100644 --- a/package/MDAnalysis/selections/pymol.py +++ b/package/MDAnalysis/selections/pymol.py @@ -59,4 +59,6 @@ def _index(atom): def _write_head(self, out, **kwargs): out.write(self.comment("MDAnalysis PyMol selection")) - out.write("select {name!s}, ".format(**kwargs) + self.continuation + "\n") + out.write( + "select {name!s}, ".format(**kwargs) + self.continuation + "\n" + ) diff --git a/package/MDAnalysis/topology/CRDParser.py b/package/MDAnalysis/topology/CRDParser.py index 84a944d4bd..c0322824ba 100644 --- a/package/MDAnalysis/topology/CRDParser.py +++ b/package/MDAnalysis/topology/CRDParser.py @@ -103,7 +103,9 @@ def parse(self, **kwargs): ---- Could use the resnum and temp factor better """ - extformat = FORTRANReader("2I10,2X,A8,2X,A8,3F20.10,2X,A8,2X,A8,F20.10") + extformat = FORTRANReader( + "2I10,2X,A8,2X,A8,3F20.10,2X,A8,2X,A8,F20.10" + ) stdformat = FORTRANReader("2I5,1X,A4,1X,A4,3F10.5,1X,A4,1X,A4,F10.5") atomids = [] @@ -122,7 +124,10 @@ def parse(self, **kwargs): elif line.split()[-1] == "EXT" and int(line.split()[0]): r = extformat continue - elif line.split()[0] == line.split()[-1] and line.split()[0] != "*": + elif ( + line.split()[0] == line.split()[-1] + and line.split()[0] != "*" + ): r = stdformat continue # anything else should be an atom @@ -141,7 +146,8 @@ def parse(self, **kwargs): ) = r.read(line) except Exception: errmsg = ( - f"Check CRD format at line {linenum + 1}: " f"{line.rstrip()}" + f"Check CRD format at line {linenum + 1}: " + f"{line.rstrip()}" ) raise ValueError(errmsg) from None @@ -163,7 +169,9 @@ def parse(self, **kwargs): segids = np.array(segids, dtype=object) atom_residx, (res_resids, res_resnames, res_resnums, res_segids) = ( - change_squash((resids, resnames), (resids, resnames, resnums, segids)) + change_squash( + (resids, resnames), (resids, resnames, resnums, segids) + ) ) res_segidx, (seg_segids,) = change_squash((res_segids,), (res_segids,)) diff --git a/package/MDAnalysis/topology/DMSParser.py b/package/MDAnalysis/topology/DMSParser.py index 3f3d988ac2..691b47eed6 100644 --- a/package/MDAnalysis/topology/DMSParser.py +++ b/package/MDAnalysis/topology/DMSParser.py @@ -201,7 +201,9 @@ def dict_factory(cursor, row): topattrs.append(Resnames(res_resnames)) if any(res_segids) and not any(val is None for val in res_segids): - res_segidx, (res_segids,) = change_squash((res_segids,), (res_segids,)) + res_segidx, (res_segids,) = change_squash( + (res_segids,), (res_segids,) + ) uniq_seg = np.unique(res_segids) idx2seg = {idx: res_segids[idx] for idx in res_segidx} diff --git a/package/MDAnalysis/topology/GMSParser.py b/package/MDAnalysis/topology/GMSParser.py index 41e55f4677..41e85f73ec 100644 --- a/package/MDAnalysis/topology/GMSParser.py +++ b/package/MDAnalysis/topology/GMSParser.py @@ -100,7 +100,9 @@ def parse(self, **kwargs): line = inf.readline() if not line: raise EOFError - if re.match(r"^\s+ATOM\s+ATOMIC\s+COORDINATES\s*\(BOHR\).*", line): + if re.match( + r"^\s+ATOM\s+ATOMIC\s+COORDINATES\s*\(BOHR\).*", line + ): break line = inf.readline() # skip diff --git a/package/MDAnalysis/topology/GSDParser.py b/package/MDAnalysis/topology/GSDParser.py index 86ff832270..45f7e570b0 100644 --- a/package/MDAnalysis/topology/GSDParser.py +++ b/package/MDAnalysis/topology/GSDParser.py @@ -139,7 +139,9 @@ def parse(self, **kwargs): # set radii, masses, charges p = snap.particles - attrs["diameter"] = Radii(np.array(p.diameter / 2.0, dtype=np.float32)) + attrs["diameter"] = Radii( + np.array(p.diameter / 2.0, dtype=np.float32) + ) attrs["mass"] = Masses(np.array(p.mass, dtype=np.float64)) attrs["charge"] = Charges(np.array(p.charge, dtype=np.float32)) diff --git a/package/MDAnalysis/topology/ITPParser.py b/package/MDAnalysis/topology/ITPParser.py index 6952db1aea..1aa87b3864 100644 --- a/package/MDAnalysis/topology/ITPParser.py +++ b/package/MDAnalysis/topology/ITPParser.py @@ -368,7 +368,9 @@ def parse_dihedrals(self, line): funct_values=(1, 3, 5, 8, 9, 10, 11), ) if not dih: - self.add_param(line, self.impropers, n_funct=4, funct_values=(2, 4)) + self.add_param( + line, self.impropers, n_funct=4, funct_values=(2, 4) + ) def parse_constraints(self, line): self.add_param(line, self.bonds, n_funct=2, funct_values=(1, 2)) @@ -405,7 +407,9 @@ def resolve_residue_attrs(self): self.resolved_residue_attrs = True - def shift_indices(self, atomid=0, resid=0, molnum=0, cgnr=0, n_res=0, n_atoms=0): + def shift_indices( + self, atomid=0, resid=0, molnum=0, cgnr=0, n_res=0, n_atoms=0 + ): """ Get attributes ready for adding onto a larger topology. @@ -573,7 +577,9 @@ def parse( self.parser = self.parse_molecules elif self.current_mol: - self.parser = self.current_mol.parsers.get(section, self._pass) + self.parser = self.current_mol.parsers.get( + section, self._pass + ) else: self.parser = self._pass @@ -593,14 +599,22 @@ def parse( if not all(self.charges): empty = self.charges == "" self.charges[empty] = [ - (self.atomtypes.get(x)["charge"] if x in self.atomtypes.keys() else "") + ( + self.atomtypes.get(x)["charge"] + if x in self.atomtypes.keys() + else "" + ) for x in self.types[empty] ] if not all(self.masses): empty = self.masses == "" self.masses[empty] = [ - (self.atomtypes.get(x)["mass"] if x in self.atomtypes.keys() else "") + ( + self.atomtypes.get(x)["mass"] + if x in self.atomtypes.keys() + else "" + ) for x in self.types[empty] ] @@ -620,11 +634,15 @@ def parse( empty = self.masses == "" self.masses[empty] = Masses.missing_value_label - attrs.append(Masses(np.array(self.masses, dtype=np.float64), guessed=False)) + attrs.append( + Masses(np.array(self.masses, dtype=np.float64), guessed=False) + ) self.elements = DefaultGuesser(None).guess_types(self.types) if all(e.capitalize() in SYMB2Z for e in self.elements): - attrs.append(Elements(np.array(self.elements, dtype=object), guessed=True)) + attrs.append( + Elements(np.array(self.elements, dtype=object), guessed=True) + ) warnings.warn( "The elements attribute has been populated by guessing " "elements from atom types. This behaviour has been " diff --git a/package/MDAnalysis/topology/LAMMPSParser.py b/package/MDAnalysis/topology/LAMMPSParser.py index cb5d4f07b5..61404fbbe7 100644 --- a/package/MDAnalysis/topology/LAMMPSParser.py +++ b/package/MDAnalysis/topology/LAMMPSParser.py @@ -229,7 +229,9 @@ def grab_datafile(self): header[token] = line.split(token)[0] continue - sects = {f[l]: f[l + 1 : starts[i + 1]] for i, l in enumerate(starts[:-1])} + sects = { + f[l]: f[l + 1 : starts[i + 1]] for i, l in enumerate(starts[:-1]) + } return header, sects @@ -315,7 +317,9 @@ def parse(self, **kwargs): (Impropers, "Impropers", 4), ]: try: - type, sect = self._parse_bond_section(sects[L], nentries, mapping) + type, sect = self._parse_bond_section( + sects[L], nentries, mapping + ) except KeyError: type, sect = [], [] @@ -323,7 +327,9 @@ def parse(self, **kwargs): return top - def read_DATA_timestep(self, n_atoms, TS_class, TS_kwargs, atom_style=None): + def read_DATA_timestep( + self, n_atoms, TS_class, TS_kwargs, atom_style=None + ): """Read a DATA file and try and extract x, v, box. - positions @@ -356,7 +362,9 @@ def read_DATA_timestep(self, n_atoms, TS_class, TS_kwargs, atom_style=None): else: velocities = None - ts = TS_class.from_coordinates(positions, velocities=velocities, **TS_kwargs) + ts = TS_class.from_coordinates( + positions, velocities=velocities, **TS_kwargs + ) ts.dimensions = unitcell return ts @@ -443,7 +451,9 @@ def _parse_bond_section(self, datalines, nentries, mapping): for line in datalines: line = line.split() # map to 0 based int - section.append(tuple([mapping[int(x)] for x in line[2 : 2 + nentries]])) + section.append( + tuple([mapping[int(x)] for x in line[2 : 2 + nentries]]) + ) type.append(line[1]) return tuple(type), tuple(section) @@ -544,7 +554,9 @@ def _parse_atoms(self, datalines, massdict=None): attrs.append(Resnums(resids.copy())) attrs.append(Segids(np.array(["SYSTEM"], dtype=object))) - top = Topology(n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx) + top = Topology( + n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx + ) return top @@ -717,7 +729,9 @@ def parse(self, **kwargs): attrs.append(DUMP_HEADERS[key]["attr_class"](value[order])) attrs.append(Segids(np.array(["SYSTEM"], dtype=object))) - return Topology(natoms, n_residues, 1, attrs=attrs, atom_resindex=residx) + return Topology( + natoms, n_residues, 1, attrs=attrs, atom_resindex=residx + ) @functools.total_ordering diff --git a/package/MDAnalysis/topology/MMTFParser.py b/package/MDAnalysis/topology/MMTFParser.py index c2b5aa0a1a..38711115bc 100644 --- a/package/MDAnalysis/topology/MMTFParser.py +++ b/package/MDAnalysis/topology/MMTFParser.py @@ -204,7 +204,12 @@ def iter_atoms(field): attrs.append(Atomids(np.arange(natoms), guessed=True)) if mtop.alt_loc_list: attrs.append( - AltLocs([val.replace("\x00", "").strip() for val in mtop.alt_loc_list]) + AltLocs( + [ + val.replace("\x00", "").strip() + for val in mtop.alt_loc_list + ] + ) ) else: attrs.append(AltLocs([""] * natoms)) @@ -229,7 +234,12 @@ def iter_atoms(field): # mmtf empty icode is '\x00' rather than '' if mtop.ins_code_list: attrs.append( - ICodes([val.replace("\x00", "").strip() for val in mtop.ins_code_list]) + ICodes( + [ + val.replace("\x00", "").strip() + for val in mtop.ins_code_list + ] + ) ) else: attrs.append(ICodes([""] * nresidues)) @@ -276,7 +286,9 @@ def iter_atoms(field): offset += groupID_2_natoms[gtype] # add inter group bonds if not mtop.bond_atom_list is None: # optional field - for x, y in zip(mtop.bond_atom_list[1::2], mtop.bond_atom_list[::2]): + for x, y in zip( + mtop.bond_atom_list[1::2], mtop.bond_atom_list[::2] + ): if x > y: x, y = y, x bonds.append((x, y)) diff --git a/package/MDAnalysis/topology/MOL2Parser.py b/package/MDAnalysis/topology/MOL2Parser.py index 488a143816..114633c0c4 100644 --- a/package/MDAnalysis/topology/MOL2Parser.py +++ b/package/MDAnalysis/topology/MOL2Parser.py @@ -197,7 +197,9 @@ def parse(self, **kwargs): for a in atom_lines: columns = a.split() if len(columns) >= 9: - aid, name, x, y, z, atom_type, resid, resname, charge = columns[:9] + aid, name, x, y, z, atom_type, resid, resname, charge = ( + columns[:9] + ) elif len(columns) < 6: raise ValueError( f"The @ATOM block in mol2 file" @@ -303,6 +305,8 @@ def parse(self, **kwargs): bonds.append(bond) attrs.append(Bonds(bonds, order=bondorder)) - top = Topology(n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx) + top = Topology( + n_atoms, n_residues, 1, attrs=attrs, atom_resindex=residx + ) return top diff --git a/package/MDAnalysis/topology/PDBParser.py b/package/MDAnalysis/topology/PDBParser.py index 9fcb19a51a..b168b0a67a 100644 --- a/package/MDAnalysis/topology/PDBParser.py +++ b/package/MDAnalysis/topology/PDBParser.py @@ -149,22 +149,16 @@ def hy36decode(width, s): int Base-10 integer corresponding to hybrid36. """ - if len(s) == width: + if (len(s) == width): f = s[0] - if f == "-" or f == " " or f.isdigit(): + if (f == "-" or f == " " or f.isdigit()): return int(s) - elif f in DIGITS_UPPER_VALUES: - return ( - decode_pure(digits_values=DIGITS_UPPER_VALUES, s=s) - - 10 * 36 ** (width - 1) - + 10**width - ) - elif f in DIGITS_LOWER_VALUES: - return ( - decode_pure(digits_values=DIGITS_LOWER_VALUES, s=s) - + 16 * 36 ** (width - 1) - + 10**width - ) + elif (f in DIGITS_UPPER_VALUES): + return decode_pure(digits_values=DIGITS_UPPER_VALUES, + s=s) - 10 * 36 ** (width - 1) + 10 ** width + elif (f in DIGITS_LOWER_VALUES): + return decode_pure(digits_values=DIGITS_LOWER_VALUES, + s=s) + 16 * 36 ** (width - 1) + 10 ** width raise ValueError("invalid number literal.") @@ -223,8 +217,7 @@ class PDBParser(TopologyReaderBase): be generated if the segids is not present or if the chainids are not completely equal to segids. """ - - format = ["PDB", "ENT"] + format = ['PDB', 'ENT'] def parse(self, **kwargs): """Parse atom information from PDB file @@ -238,11 +231,11 @@ def parse(self, **kwargs): try: bonds = self._parsebonds(top.ids.values) except AttributeError: - warnings.warn( - "Invalid atom serials were present, " "bonds will not be parsed" - ) + warnings.warn("Invalid atom serials were present, " + "bonds will not be parsed") except RuntimeError: - warnings.warn("CONECT records was corrupt, " "bonds will not be parsed") + warnings.warn("CONECT records was corrupt, " + "bonds will not be parsed") else: # Issue 2832: don't append Bonds if there are no bonds if bonds: @@ -275,9 +268,9 @@ def _parseatoms(self, **kwargs): line = line.strip() # Remove extra spaces if not line: # Skip line if empty continue - if line.startswith("END"): + if line.startswith('END'): break - if not line.startswith(("ATOM", "HETATM")): + if not line.startswith(('ATOM', 'HETATM')): continue record_types.append(line[:6].strip()) @@ -313,9 +306,8 @@ def _parseatoms(self, **kwargs): resid += 10000 resid_prev = resid except ValueError: - warnings.warn( - "PDB file is missing resid information. " "Defaulted to '1'" - ) + warnings.warn("PDB file is missing resid information. " + "Defaulted to '1'") resid = 1 finally: resids.append(resid) @@ -328,9 +320,8 @@ def _parseatoms(self, **kwargs): # Warn about wrapped serials if self._wrapped_serials: - warnings.warn( - "Serial numbers went over 100,000. " "Higher serials have been guessed" - ) + warnings.warn("Serial numbers went over 100,000. " + "Higher serials have been guessed") # If segids is not equal to chainids, warn the user if any([a != b for a, b in zip(segids, chainids)]): @@ -338,17 +329,14 @@ def _parseatoms(self, **kwargs): # If segids not present, try to use chainids if not any(segids): - logger.info( - "Setting segids from chainIDs because no segids " - "found in the PDB file." - ) + logger.info("Setting segids from chainIDs because no segids " + "found in the PDB file.") segids = chainids # If force_chainids_to_segids is set, use chainids as segids if kwargs.get("force_chainids_to_segids", False): - logger.info( - "force_chainids_to_segids is set. " "Using chain IDs as segment IDs." - ) + logger.info("force_chainids_to_segids is set. " + "Using chain IDs as segment IDs.") segids = chainids n_atoms = len(serials) @@ -356,13 +344,13 @@ def _parseatoms(self, **kwargs): attrs = [] # Make Atom TopologyAttrs for vals, Attr, dtype in ( - (names, Atomnames, object), - (altlocs, AltLocs, object), - (chainids, ChainIDs, object), - (record_types, RecordTypes, object), - (serials, Atomids, np.int32), - (tempfactors, Tempfactors, np.float32), - (occupancies, Occupancies, np.float32), + (names, Atomnames, object), + (altlocs, AltLocs, object), + (chainids, ChainIDs, object), + (record_types, RecordTypes, object), + (serials, Atomids, np.int32), + (tempfactors, Tempfactors, np.float32), + (occupancies, Occupancies, np.float32), ): attrs.append(Attr(np.array(vals, dtype=dtype))) # OPT: We do this check twice, maybe could refactor to avoid this @@ -376,47 +364,41 @@ def _parseatoms(self, **kwargs): if elem.capitalize() in SYMB2Z: validated_elements.append(elem.capitalize()) else: - wmsg = ( - f"Unknown element {elem} found for some atoms. " - f"These have been given an empty element record. " - f"If needed they can be guessed using " - f"universe.guess_TopologyAttrs(context='default'," - " to_guess=['elements'])." - ) + wmsg = (f"Unknown element {elem} found for some atoms. " + f"These have been given an empty element record. " + f"If needed they can be guessed using " + f"universe.guess_TopologyAttrs(context='default'," + " to_guess=['elements']).") warnings.warn(wmsg) - validated_elements.append("") + validated_elements.append('') attrs.append(Elements(np.array(validated_elements, dtype=object))) else: - warnings.warn( - "Element information is missing, elements attribute " - "will not be populated. If needed these can be" - " guessed using universe.guess_TopologyAttrs(" - "context='default', to_guess=['elements'])." - ) + warnings.warn("Element information is missing, elements attribute " + "will not be populated. If needed these can be" + " guessed using universe.guess_TopologyAttrs(" + "context='default', to_guess=['elements']).") if any(formalcharges): try: for i, entry in enumerate(formalcharges): - if not entry == "": - if entry == "0": + if not entry == '': + if entry == '0': # Technically a lack of charge shouldn't be in the # PDB but MDA has a few files that specifically # have 0 entries, indicating that some folks # interpret 0 as an allowed entry formalcharges[i] = 0 - elif ("+" in entry) or ("-" in entry): + elif ('+' in entry) or ('-' in entry): formalcharges[i] = int(entry[::-1]) else: raise ValueError else: formalcharges[i] = 0 except ValueError: - wmsg = ( - f"Unknown entry {entry} encountered in formal charge " - "field. This likely indicates that the PDB file is " - "not fully standard compliant. The formalcharges " - "attribute will not be populated." - ) + wmsg = (f"Unknown entry {entry} encountered in formal charge " + "field. This likely indicates that the PDB file is " + "not fully standard compliant. The formalcharges " + "attribute will not be populated.") warnings.warn(wmsg) else: attrs.append(FormalCharges(np.array(formalcharges, dtype=int))) @@ -424,45 +406,38 @@ def _parseatoms(self, **kwargs): # Residue level stuff from here resids = np.array(resids, dtype=np.int32) resnames = np.array(resnames, dtype=object) - if self.format == "XPDB": # XPDB doesn't have icodes - icodes = [""] * n_atoms + if self.format == 'XPDB': # XPDB doesn't have icodes + icodes = [''] * n_atoms icodes = np.array(icodes, dtype=object) resnums = resids.copy() segids = np.array(segids, dtype=object) residx, (resids, resnames, icodes, resnums, segids) = change_squash( - (resids, resnames, icodes, segids), - (resids, resnames, icodes, resnums, segids), - ) + (resids, resnames, icodes, segids), (resids, resnames, icodes, resnums, segids)) n_residues = len(resids) attrs.append(Resnums(resnums)) attrs.append(Resids(resids)) attrs.append(ICodes(icodes)) attrs.append(Resnames(resnames)) - if kwargs.get("force_chainids_to_segids", False) or ( - any(segids) and not any(val is None for val in segids) + if ( + kwargs.get("force_chainids_to_segids", False) or + (any(segids) and not any(val is None for val in segids)) ): segidx, (segids,) = change_squash((segids,), (segids,)) n_segments = len(segids) attrs.append(Segids(segids)) else: n_segments = 1 - attrs.append(Segids(np.array(["SYSTEM"], dtype=object))) + attrs.append(Segids(np.array(['SYSTEM'], dtype=object))) segidx = None - logger.info( - "Segment/chain ID is empty, " - "setting segids to default value 'SYSTEM'." - ) - - top = Topology( - n_atoms, - n_residues, - n_segments, - attrs=attrs, - atom_resindex=residx, - residue_segindex=segidx, - ) + logger.info("Segment/chain ID is empty, " + "setting segids to default value 'SYSTEM'.") + + top = Topology(n_atoms, n_residues, n_segments, + attrs=attrs, + atom_resindex=residx, + residue_segindex=segidx) return top @@ -475,9 +450,8 @@ def _parsebonds(self, serials): # If the serials wrapped, this won't work if self._wrapped_serials: - warnings.warn( - "Invalid atom serials were present, bonds will not" " be parsed" - ) + warnings.warn("Invalid atom serials were present, bonds will not" + " be parsed") raise AttributeError # gets caught in parse # Mapping between the atom array indicies a.index and atom ids @@ -497,8 +471,7 @@ def _parsebonds(self, serials): # Ignore these as they are not real atoms warnings.warn( "PDB file contained CONECT record to TER entry. " - "These are not included in bonds." - ) + "These are not included in bonds.") else: bonds.add(bond) @@ -532,14 +505,13 @@ def _parse_conect(conect): try: if len(conect[11:]) % n_bond_atoms != 0: - raise RuntimeError( - "Bond atoms aren't aligned proberly for CONECT " - "record: {}".format(conect) - ) + raise RuntimeError("Bond atoms aren't aligned proberly for CONECT " + "record: {}".format(conect)) except ZeroDivisionError: # Conect record with only one entry (CONECT A\n) warnings.warn("Found CONECT record with single entry, ignoring this") return atom_id, [] # return empty list to allow iteration over nothing - bond_atoms = (int(conect[11 + i * 5 : 16 + i * 5]) for i in range(n_bond_atoms)) + bond_atoms = (int(conect[11 + i * 5: 16 + i * 5]) for i in + range(n_bond_atoms)) return atom_id, bond_atoms diff --git a/package/MDAnalysis/topology/PSFParser.py b/package/MDAnalysis/topology/PSFParser.py index 2101366c90..531c2ae592 100644 --- a/package/MDAnalysis/topology/PSFParser.py +++ b/package/MDAnalysis/topology/PSFParser.py @@ -132,7 +132,8 @@ def parse(self, **kwargs): for _ in range(int(title[0])): next(psffile) logger.debug( - "PSF file {0}: format {1}" "".format(self.filename, self._format) + "PSF file {0}: format {1}" + "".format(self.filename, self._format) ) # Atoms first and mandatory @@ -177,7 +178,9 @@ def _parse_sec(self, psffile, section_info): sect_type = header[1].strip("!:") # Make sure the section type matches the desc if not sect_type == desc: - err = "Expected section {0} but found {1}" "".format(desc, sect_type) + err = "Expected section {0} but found {1}" "".format( + desc, sect_type + ) logger.error(err) raise ValueError(err) # Now figure out how many lines to read @@ -316,7 +319,8 @@ def _parseatoms(self, lines, atoms_per, numlines): " continuing with fingers crossed!" ) logger.debug( - "First NAMD-type line: {0}: {1}" "".format(i, line.rstrip()) + "First NAMD-type line: {0}: {1}" + "".format(i, line.rstrip()) ) atomids[i] = vals[0] diff --git a/package/MDAnalysis/topology/TOPParser.py b/package/MDAnalysis/topology/TOPParser.py index 7f90e18464..ba61bea0b0 100644 --- a/package/MDAnalysis/topology/TOPParser.py +++ b/package/MDAnalysis/topology/TOPParser.py @@ -256,9 +256,9 @@ def parse(self, **kwargs): while next_section is not None: try: - (num_per_record, per_line, func, name, sect_num) = sections[ - next_section - ] + (num_per_record, per_line, func, name, sect_num) = ( + sections[next_section] + ) except KeyError: def next_getter(): @@ -305,7 +305,12 @@ def next_getter(): # Deal with recreating bonds and angle records here attrs["bonds"] = Bonds( - [i for i in itertools.chain(attrs.pop("bonda"), attrs.pop("bondh"))] + [ + i + for i in itertools.chain( + attrs.pop("bonda"), attrs.pop("bondh") + ) + ] ) attrs["angles"] = Angles( @@ -344,7 +349,9 @@ def next_getter(): # Amber's 'RESIDUE_CHAINID' is a by-residue attribute, turn it into # a by-atom attribute when present. See PR #4007. if "segids" in attrs and len(attrs["segids"]) == n_res: - segidx, (segids,) = change_squash((attrs["segids"],), (attrs["segids"],)) + segidx, (segids,) = change_squash( + (attrs["segids"],), (attrs["segids"],) + ) chainids = [attrs["segids"][r] for r in residx] attrs["segids"] = Segids(segids) @@ -587,7 +594,8 @@ def parse_chunks(self, data, chunksize): into chunks of size num_per_record, and only extract the atom ids. """ vals = [ - tuple(data[x : x + chunksize - 1]) for x in range(0, len(data), chunksize) + tuple(data[x : x + chunksize - 1]) + for x in range(0, len(data), chunksize) ] return vals diff --git a/package/MDAnalysis/topology/TPRParser.py b/package/MDAnalysis/topology/TPRParser.py index 08ced830fb..5fd29d1985 100644 --- a/package/MDAnalysis/topology/TPRParser.py +++ b/package/MDAnalysis/topology/TPRParser.py @@ -242,7 +242,9 @@ def parse(self, tpr_resid_from_one=True, **kwargs): if state_ngtc > 0: if th.fver < 69: # redundancy due to different versions tpr_utils.ndo_real(data, state_ngtc) - tpr_utils.ndo_real(data, state_ngtc) # relevant to Berendsen tcoupl_lambda + tpr_utils.ndo_real( + data, state_ngtc + ) # relevant to Berendsen tcoupl_lambda if th.bTop: tpr_top = tpr_utils.do_mtop( diff --git a/package/MDAnalysis/topology/__init__.py b/package/MDAnalysis/topology/__init__.py index 5adc807adc..945deaf436 100644 --- a/package/MDAnalysis/topology/__init__.py +++ b/package/MDAnalysis/topology/__init__.py @@ -311,24 +311,10 @@ """ -__all__ = [ - "core", - "PSFParser", - "PDBParser", - "PQRParser", - "GROParser", - "CRDParser", - "TOPParser", - "PDBQTParser", - "TPRParser", - "LAMMPSParser", - "XYZParser", - "GMSParser", - "DLPolyParser", - "HoomdXMLParser", - "GSDParser", - "ITPParser", -] +__all__ = ['core', 'PSFParser', 'PDBParser', 'PQRParser', 'GROParser', + 'CRDParser', 'TOPParser', 'PDBQTParser', 'TPRParser', + 'LAMMPSParser', 'XYZParser', 'GMSParser', 'DLPolyParser', + 'HoomdXMLParser','GSDParser', 'ITPParser'] from . import core from . import PSFParser diff --git a/package/MDAnalysis/topology/base.py b/package/MDAnalysis/topology/base.py index 7462845e5a..f4ae0894e4 100644 --- a/package/MDAnalysis/topology/base.py +++ b/package/MDAnalysis/topology/base.py @@ -77,11 +77,10 @@ class ThingParser(TopologyReaderBase): .. versionchanged:: 1.0.0 Added format_hint functionality """ - def __init__(cls, name, bases, classdict): type.__init__(type, name, bases, classdict) try: - fmt = util.asiterable(classdict["format"]) + fmt = util.asiterable(classdict['format']) except KeyError: pass else: @@ -89,9 +88,8 @@ def __init__(cls, name, bases, classdict): fmt_name = fmt_name.upper() _PARSERS[fmt_name] = cls - if "_format_hint" in classdict: - _PARSER_HINTS[fmt_name] = classdict["_format_hint"].__func__ - + if '_format_hint' in classdict: + _PARSER_HINTS[fmt_name] = classdict['_format_hint'].__func__ class TopologyReaderBase(IOBase, metaclass=_Topologymeta): """Base class for topology readers @@ -116,7 +114,6 @@ class TopologyReaderBase(IOBase, metaclass=_Topologymeta): .. versionchanged:: 0.9.2 Added keyword 'universe' to pass to Atom creation. """ - def __init__(self, filename): self.filename = filename @@ -140,8 +137,7 @@ def squash_by(child_parent_ids, *attributes): *parent_attrs - len(parent) of the other attributes """ unique_resids, sort_mask, atom_idx = np.unique( - child_parent_ids, return_index=True, return_inverse=True - ) + child_parent_ids, return_index=True, return_inverse=True) return atom_idx, unique_resids, [attr[sort_mask] for attr in attributes] @@ -180,15 +176,16 @@ def change_squash(criteria, to_squash): new_resnames: ['RsA', 'RsB', 'RsC'] new_segids: ['A', 'A', 'B'] """ - def get_borders(*arrays): """Generator of indices to slice arrays when they change""" - borders = np.nonzero(reduce(np.logical_or, (a[:-1] != a[1:] for a in arrays))) + borders = np.nonzero(reduce(np.logical_or, + (a[:-1] != a[1:] for a in arrays))) # Add Nones so we can slice from start to end return [None] + list(borders[0] + 1) + [None] l0 = len(criteria[0]) - if not all(len(other) == l0 for other in itertools.chain(criteria[1:], to_squash)): + if not all(len(other) == l0 + for other in itertools.chain(criteria[1:], to_squash)): raise ValueError("All arrays must be equally sized") # 1) Detect where resids change diff --git a/package/MDAnalysis/topology/guessers.py b/package/MDAnalysis/topology/guessers.py index 383346f684..6ae316cd02 100644 --- a/package/MDAnalysis/topology/guessers.py +++ b/package/MDAnalysis/topology/guessers.py @@ -180,7 +180,9 @@ def guess_types(atom_names): ------- atom_types : np.ndarray dtype object """ - return np.array([guess_atom_element(name) for name in atom_names], dtype=object) + return np.array( + [guess_atom_element(name) for name in atom_names], dtype=object + ) @deprecate(release="2.8.0", remove="3.0.0", message=deprecation_msg) @@ -424,7 +426,9 @@ def guess_dihedrals(angles): a_tup = tuple([a.index for a in b]) # angle as tuple of numbers # if searching with b[0], want tuple of (b[2], b[1], b[0], +new) # search the first and last atom of each angle - for atom, prefix in zip([b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup]): + for atom, prefix in zip( + [b.atoms[0], b.atoms[-1]], [a_tup[::-1], a_tup] + ): for other_b in atom.bonds: if not other_b.partner(atom) in b: third_a = other_b.partner(atom) diff --git a/package/MDAnalysis/topology/tpr/obj.py b/package/MDAnalysis/topology/tpr/obj.py index abb6ae6f88..93c5a83ee7 100644 --- a/package/MDAnalysis/topology/tpr/obj.py +++ b/package/MDAnalysis/topology/tpr/obj.py @@ -139,7 +139,9 @@ def remap_impr(self, atom_start_ndx): class AtomKind(object): - def __init__(self, id, name, type, resid, resname, mass, charge, atomic_number): + def __init__( + self, id, name, type, resid, resname, mass, charge, atomic_number + ): # id is only within the scope of a single molecule, not the whole system self.id = id self.name = name diff --git a/package/MDAnalysis/topology/tpr/utils.py b/package/MDAnalysis/topology/tpr/utils.py index 83a1b6f32e..a332181392 100644 --- a/package/MDAnalysis/topology/tpr/utils.py +++ b/package/MDAnalysis/topology/tpr/utils.py @@ -79,7 +79,6 @@ class TPXUnpacker(xdrlib.Unpacker): """ Extend the standard XDR unpacker for the specificity of TPX files. """ - def __init__(self, data): super().__init__(data) self._buf = self.get_buffer() @@ -104,10 +103,10 @@ def _unpack_value(self, item_size, struct_template): return struct.unpack(struct_template, content)[0] def unpack_int64(self): - return self._unpack_value(8, ">q") + return self._unpack_value(8, '>q') def unpack_uint64(self): - return self._unpack_value(8, ">Q") + return self._unpack_value(8, '>Q') def unpack_ushort(self): return self.unpack_uint() @@ -115,7 +114,7 @@ def unpack_ushort(self): def unpack_uchar(self): # TPX files prior to gromacs 2020 (tpx version < 119) use unsigned ints # (4 bytes) instead of unsigned chars. - return self._unpack_value(4, ">I") + return self._unpack_value(4, '>I') def do_string(self): """ @@ -139,12 +138,11 @@ class TPXUnpacker2020(TPXUnpacker): gromacs 2020, changes le meaning of some types in the file body (the header keep using the previous implementation of the serializer). """ - @classmethod def from_unpacker(cls, unpacker): new_unpacker = cls(unpacker.get_buffer()) new_unpacker._pos = unpacker.get_position() - if hasattr(unpacker, "unpack_real"): + if hasattr(unpacker, 'unpack_real'): if unpacker.unpack_real == unpacker.unpack_float: new_unpacker.unpack_real = new_unpacker.unpack_float elif unpacker.unpack_real == unpacker.unpack_double: @@ -155,7 +153,7 @@ def from_unpacker(cls, unpacker): def unpack_fstring(self, n): if n < 0: - raise ValueError("Size of fstring cannot be negative.") + raise ValueError('Size of fstring cannot be negative.') start_position = self._pos end_position = self._pos = start_position + n if end_position > len(self._buf): @@ -166,12 +164,12 @@ def unpack_fstring(self, n): def unpack_ushort(self): # The InMemorySerializer implements ushort according to the XDR standard # on the contrary to the IO serializer. - return self._unpack_value(2, ">H") + return self._unpack_value(2, '>H') def unpack_uchar(self): # The InMemorySerializer implements uchar according to the XDR standard # on the contrary to the IO serializer. - return self._unpack_value(1, ">B") + return self._unpack_value(1, '>B') def do_string(self): """ @@ -223,11 +221,12 @@ def define_unpack_real(prec, data): def read_tpxheader(data): - """this function is now compatible with do_tpxheader in tpxio.cpp""" + """this function is now compatible with do_tpxheader in tpxio.cpp + """ # Last compatibility check with gromacs-2016 ver_str = data.do_string() # version string e.g. VERSION 4.0.5 - if not ver_str.startswith(b"VERSION"): - raise ValueError("Input does not look like a TPR file.") + if not ver_str.startswith(b'VERSION'): + raise ValueError('Input does not look like a TPR file.') precision = data.unpack_int() # e.g. 4 define_unpack_real(precision, data) fileVersion = data.unpack_int() # version of tpx file @@ -240,9 +239,7 @@ def read_tpxheader(data): data.unpack_int() # the value is 8, but haven't found the file_tag = data.do_string() - fileGeneration = ( - data.unpack_int() if fileVersion >= 26 else 0 - ) # generation of tpx file, e.g. 17 + fileGeneration = data.unpack_int() if fileVersion >= 26 else 0 # generation of tpx file, e.g. 17 # Versions before 77 don't have the tag, set it to TPX_TAG_RELEASE file_tag # file_tag is used for comparing with tpx_tag. Only tpr files with a @@ -252,9 +249,7 @@ def read_tpxheader(data): file_tag = data.do_string() if fileVersion >= 81 else setting.TPX_TAG_RELEASE natoms = data.unpack_int() # total number of atoms - ngtc = ( - data.unpack_int() if fileVersion >= 28 else 0 - ) # number of groups for T-coupling + ngtc = data.unpack_int() if fileVersion >= 28 else 0 # number of groups for T-coupling if fileVersion < 62: # not sure what these two are for. @@ -277,24 +272,9 @@ def read_tpxheader(data): if fileVersion >= setting.tpxv_AddSizeField and fileGeneration >= 27: sizeOfTprBody = data.unpack_int64() - th = obj.TpxHeader( - ver_str, - precision, - fileVersion, - fileGeneration, - file_tag, - natoms, - ngtc, - fep_state, - lamb, - bIr, - bTop, - bX, - bV, - bF, - bBox, - sizeOfTprBody, - ) + th = obj.TpxHeader(ver_str, precision, fileVersion, fileGeneration, + file_tag, natoms, ngtc, fep_state, lamb, + bIr, bTop, bX, bV, bF, bBox, sizeOfTprBody) return th @@ -348,7 +328,7 @@ def do_mtop(data, fver, tpr_resid_from_one=False): mb = do_molblock(data) # segment is made to correspond to the molblock as in gromacs, the # naming is kind of arbitrary - molblock = mtop.moltypes[mb.molb_type].name.decode("utf-8") + molblock = mtop.moltypes[mb.molb_type].name.decode('utf-8') segid = f"seg_{i}_{molblock}" chainID = molblock[14:] if molblock[:14] == "Protein_chain_" else molblock for j in range(mb.molb_nmol): @@ -392,9 +372,17 @@ def do_mtop(data, fver, tpr_resid_from_one=False): resids += 1 resnames = np.array(resnames, dtype=object) - (residx, new_resids, (new_resnames, new_moltypes, new_molnums, perres_segids)) = ( - squash_by(resids, resnames, moltypes, molnums, segids) - ) + (residx, new_resids, + (new_resnames, + new_moltypes, + new_molnums, + perres_segids + ) + ) = squash_by(resids, + resnames, + moltypes, + molnums, + segids) residueids = Resids(new_resids) residuenames = Resnames(new_resnames) residue_moltypes = Moltypes(new_moltypes) @@ -426,8 +414,10 @@ def do_mtop(data, fver, tpr_resid_from_one=False): ) top.add_TopologyAttr(Bonds([bond for bond in bonds if bond])) top.add_TopologyAttr(Angles([angle for angle in angles if angle])) - top.add_TopologyAttr(Dihedrals([dihedral for dihedral in dihedrals if dihedral])) - top.add_TopologyAttr(Impropers([improper for improper in impropers if improper])) + top.add_TopologyAttr(Dihedrals([dihedral for dihedral in dihedrals + if dihedral])) + top.add_TopologyAttr(Impropers([improper for improper in impropers + if improper])) if any(elements): elements = Elements(np.array(elements, dtype=object)) @@ -483,12 +473,9 @@ def do_iparams(data, functypes, fver): # Not all elif cases in this function has been used and tested for k, i in enumerate(functypes): if i in [ - setting.F_ANGLES, - setting.F_G96ANGLES, - setting.F_BONDS, - setting.F_G96BONDS, - setting.F_HARMONIC, - setting.F_IDIHS, + setting.F_ANGLES, setting.F_G96ANGLES, + setting.F_BONDS, setting.F_G96BONDS, + setting.F_HARMONIC, setting.F_IDIHS ]: do_harm(data) elif i in [setting.F_RESTRANGLES]: @@ -516,10 +503,8 @@ def do_iparams(data, functypes, fver): data.unpack_real() # restraint.up2B data.unpack_real() # restraint.kB elif i in [ - setting.F_TABBONDS, - setting.F_TABBONDSNC, - setting.F_TABANGLES, - setting.F_TABDIHS, + setting.F_TABBONDS, setting.F_TABBONDSNC, + setting.F_TABANGLES, setting.F_TABDIHS, ]: data.unpack_real() # tab.kA data.unpack_int() # tab.table @@ -545,7 +530,7 @@ def do_iparams(data, functypes, fver): data.unpack_real() # u_b.kUBB elif i in [setting.F_QUARTIC_ANGLES]: data.unpack_real() # qangle.theta - ndo_real(data, 5) # qangle.c + ndo_real(data, 5) # qangle.c elif i in [setting.F_BHAM]: data.unpack_real() # bham.a data.unpack_real() # bham.b @@ -605,10 +590,8 @@ def do_iparams(data, functypes, fver): data.unpack_real() # ljcnb.c12 elif i in [ - setting.F_PIDIHS, - setting.F_ANGRES, - setting.F_ANGRESZ, - setting.F_PDIHS, + setting.F_PIDIHS, setting.F_ANGRES, + setting.F_ANGRESZ, setting.F_PDIHS, ]: data.unpack_real() # pdihs_phiA data.unpack_real() # pdihs_cpA @@ -657,8 +640,8 @@ def do_iparams(data, functypes, fver): do_rvec(data) # posres.fcB elif i in [setting.F_FBPOSRES]: - data.unpack_int() # fbposres.geom - do_rvec(data) # fbposres.pos0 + data.unpack_int() # fbposres.geom + do_rvec(data) # fbposres.pos0 data.unpack_real() # fbposres.r data.unpack_real() # fbposres.k @@ -737,18 +720,16 @@ def do_moltype(data, symtab, fver): #### start: MDAnalysis specific atomkinds = [] for k, a in enumerate(atoms_obj.atoms): - atomkinds.append( - obj.AtomKind( - k, - atoms_obj.atomnames[k], - atoms_obj.type[k], - a.resind, - atoms_obj.resnames[a.resind], - a.m, - a.q, - a.atomnumber, - ) - ) + atomkinds.append(obj.AtomKind( + k, + atoms_obj.atomnames[k], + atoms_obj.type[k], + a.resind, + atoms_obj.resnames[a.resind], + a.m, + a.q, + a.atomnumber, + )) #### end: MDAnalysis specific # key info: about bonds, angles, dih, improp dih. @@ -764,44 +745,21 @@ def do_moltype(data, symtab, fver): # the following if..elif..else statement needs to be updated as new # type of interactions become interested - if ik_obj.name in [ - "BONDS", - "G96BONDS", - "MORSE", - "CUBICBONDS", - "CONNBONDS", - "HARMONIC", - "FENEBONDS", - "RESTRAINTPOT", - "CONSTR", - "CONSTRNC", - "TABBONDS", - "TABBONDSNC", - ]: + if ik_obj.name in ['BONDS', 'G96BONDS', 'MORSE', 'CUBICBONDS', + 'CONNBONDS', 'HARMONIC', 'FENEBONDS', + 'RESTRAINTPOT', 'CONSTR', 'CONSTRNC', + 'TABBONDS', 'TABBONDSNC']: bonds += list(ik_obj.process(ias)) - elif ik_obj.name in [ - "ANGLES", - "G96ANGLES", - "CROSS_BOND_BOND", - "CROSS_BOND_ANGLE", - "UREY_BRADLEY", - "QANGLES", - "RESTRANGLES", - "TABANGLES", - ]: + elif ik_obj.name in ['ANGLES', 'G96ANGLES', 'CROSS_BOND_BOND', + 'CROSS_BOND_ANGLE', 'UREY_BRADLEY', 'QANGLES', + 'RESTRANGLES', 'TABANGLES']: angles += list(ik_obj.process(ias)) - elif ik_obj.name in [ - "PDIHS", - "RBDIHS", - "RESTRDIHS", - "CBTDIHS", - "FOURDIHS", - "TABDIHS", - ]: + elif ik_obj.name in ['PDIHS', 'RBDIHS', 'RESTRDIHS', 'CBTDIHS', + 'FOURDIHS', 'TABDIHS']: dihs += list(ik_obj.process(ias)) - elif ik_obj.name in ["IDIHS", "PIDIHS"]: + elif ik_obj.name in ['IDIHS', 'PIDIHS']: impr += list(ik_obj.process(ias)) - elif ik_obj.name == "SETTLE": + elif ik_obj.name == 'SETTLE': # SETTLE interactions are optimized triangular constraints for # water molecules. They should be counted as a pair of bonds # between the oxygen and the hydrogens. In older versions of @@ -908,7 +866,8 @@ def do_ilists(data, fver): iatoms.append(l_) return [ - obj.Ilist(n, it, i) for n, it, i in zip(nr, setting.interaction_types, iatoms) + obj.Ilist(n, it, i) + for n, it, i in zip(nr, setting.interaction_types, iatoms) ] @@ -923,9 +882,8 @@ def do_molblock(data): if molb_nposres_xB > 0: ndo_rvec(data, molb_nposres_xB) - return obj.Molblock( - molb_type, molb_nmol, molb_natoms_mol, molb_nposres_xA, molb_nposres_xB - ) + return obj.Molblock(molb_type, molb_nmol, molb_natoms_mol, + molb_nposres_xA, molb_nposres_xB) def do_block(data): diff --git a/package/MDAnalysis/transformations/boxdimensions.py b/package/MDAnalysis/transformations/boxdimensions.py index 750cd55392..c18cdc36a7 100644 --- a/package/MDAnalysis/transformations/boxdimensions.py +++ b/package/MDAnalysis/transformations/boxdimensions.py @@ -87,7 +87,9 @@ class set_dimensions(TransformationBase): """ def __init__(self, dimensions, max_threads=None, parallelizable=True): - super().__init__(max_threads=max_threads, parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.dimensions = dimensions try: diff --git a/package/MDAnalysis/transformations/fit.py b/package/MDAnalysis/transformations/fit.py index 81268b9a30..89336128cb 100644 --- a/package/MDAnalysis/transformations/fit.py +++ b/package/MDAnalysis/transformations/fit.py @@ -100,7 +100,9 @@ def __init__( max_threads=None, parallelizable=True, ): - super().__init__(max_threads=max_threads, parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag self.reference = reference @@ -112,7 +114,9 @@ def __init__( 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 = ( @@ -122,7 +126,10 @@ def __init__( raise ValueError(errmsg) except AttributeError: - errmsg = f"{self.ag} or {self.reference} is not valid" f"Universe/AtomGroup" + errmsg = ( + 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 @@ -131,7 +138,9 @@ def __init__( 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 @@ -210,7 +219,9 @@ def __init__( max_threads=1, parallelizable=True, ): - super().__init__(max_threads=max_threads, parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag self.reference = reference @@ -222,7 +233,9 @@ def __init__( 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 = ( @@ -232,7 +245,8 @@ def __init__( 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( @@ -252,9 +266,13 @@ def _transform(self, ts): 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 + 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] diff --git a/package/MDAnalysis/transformations/nojump.py b/package/MDAnalysis/transformations/nojump.py index dfb2caa3c4..d4a54f6f8d 100644 --- a/package/MDAnalysis/transformations/nojump.py +++ b/package/MDAnalysis/transformations/nojump.py @@ -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 e15df72083..d091dd9bbf 100644 --- a/package/MDAnalysis/transformations/positionaveraging.py +++ b/package/MDAnalysis/transformations/positionaveraging.py @@ -148,7 +148,9 @@ def __init__( max_threads=None, parallelizable=False, ): - super().__init__(max_threads=max_threads, parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.avg_frames = avg_frames self.check_reset = check_reset self.current_avg = 0 diff --git a/package/MDAnalysis/transformations/rotate.py b/package/MDAnalysis/transformations/rotate.py index d247a83dc9..4d8fa71d0b 100644 --- a/package/MDAnalysis/transformations/rotate.py +++ b/package/MDAnalysis/transformations/rotate.py @@ -134,7 +134,9 @@ def __init__( max_threads=1, parallelizable=True, ): - super().__init__(max_threads=max_threads, parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.angle = angle self.direction = direction @@ -147,12 +149,16 @@ def __init__( 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)) + 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): @@ -164,10 +170,14 @@ def __init__( 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 " diff --git a/package/MDAnalysis/transformations/translate.py b/package/MDAnalysis/transformations/translate.py index 43f9bb10ef..c28fffd404 100644 --- a/package/MDAnalysis/transformations/translate.py +++ b/package/MDAnalysis/transformations/translate.py @@ -72,7 +72,9 @@ class translate(TransformationBase): """ def __init__(self, vector, max_threads=None, parallelizable=True): - super().__init__(max_threads=max_threads, parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.vector = vector @@ -139,7 +141,9 @@ def __init__( max_threads=None, parallelizable=True, ): - super().__init__(max_threads=max_threads, parallelizable=parallelizable) + super().__init__( + max_threads=max_threads, parallelizable=parallelizable + ) self.ag = ag self.center = center @@ -153,9 +157,13 @@ def __init__( 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) + 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) + self.center_method = partial( + self.ag.center_of_mass, wrap=pbc_arg + ) else: raise ValueError(f"{self.center} is valid for center") except AttributeError: @@ -163,7 +171,9 @@ def __init__( 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 1605925932..f8c1d8dbae 100644 --- a/package/MDAnalysis/transformations/wrap.py +++ b/package/MDAnalysis/transformations/wrap.py @@ -91,8 +91,12 @@ class wrap(TransformationBase): 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 @@ -152,7 +156,9 @@ class unwrap(TransformationBase): """ 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/MDAnalysis/units.py b/package/MDAnalysis/units.py index f123a02f2c..4f18652119 100644 --- a/package/MDAnalysis/units.py +++ b/package/MDAnalysis/units.py @@ -262,12 +262,14 @@ def __getitem__(self, key): "nm^{-3}": 1 / 1e-3, "nanometer^{-3}": 1 / 1e-3, "Molar": 1 / (1e-27 * constants["N_Avogadro"]), - "SPC": 1 / (1e-24 * constants["N_Avogadro"] * water["SPC"] / water["MolarMass"]), + "SPC": 1 + / (1e-24 * constants["N_Avogadro"] * water["SPC"] / water["MolarMass"]), "TIP3P": 1 / (1e-24 * constants["N_Avogadro"] * water["TIP3P"] / water["MolarMass"]), "TIP4P": 1 / (1e-24 * constants["N_Avogadro"] * water["TIP4P"] / water["MolarMass"]), - "water": 1 / (1e-24 * constants["N_Avogadro"] * water["exp"] / water["MolarMass"]), + "water": 1 + / (1e-24 * constants["N_Avogadro"] * water["exp"] / water["MolarMass"]), } diff --git a/package/MDAnalysis/visualization/streamlines.py b/package/MDAnalysis/visualization/streamlines.py index 6248fdb042..12534a2e77 100644 --- a/package/MDAnalysis/visualization/streamlines.py +++ b/package/MDAnalysis/visualization/streamlines.py @@ -166,7 +166,9 @@ def split_grid(grid, num_cores): list_square_vertex_arrays_per_core = np.array_split( list_all_squares_in_grid, num_cores ) - list_parent_index_values = np.array_split(list_parent_index_values, num_cores) + list_parent_index_values = np.array_split( + list_parent_index_values, num_cores + ) return [ list_square_vertex_arrays_per_core, list_parent_index_values, @@ -212,16 +214,14 @@ def _produce_list_centroids_this_frame( ): # if there are no particles of interest in this particular square list_centroids_this_frame.append(None) else: - current_coordinate_array_in_square = relevant_particle_coordinate_array_xy[ - indices - ] + current_coordinate_array_in_square = ( + relevant_particle_coordinate_array_xy[indices] + ) current_square_indices_centroid = np.average( current_coordinate_array_in_square, axis=0 ) list_centroids_this_frame.append(current_square_indices_centroid) - return ( - list_centroids_this_frame # a list of numpy xy centroid arrays for this frame - ) + return list_centroids_this_frame # a list of numpy xy centroid arrays for this frame def per_core_work( @@ -239,7 +239,9 @@ def per_core_work( The code to perform on a given core given the list of square vertices assigned to it. """ # obtain the relevant coordinates for particles of interest - universe_object = MDAnalysis.Universe(topology_file_path, trajectory_file_path) + universe_object = MDAnalysis.Universe( + topology_file_path, trajectory_file_path + ) list_previous_frame_centroids = [] list_previous_frame_indices = [] for ts in universe_object.trajectory: @@ -257,9 +259,11 @@ def per_core_work( ) ) # likewise, I will need a list of centroids of particles in each square (same order as above list): - list_centroids_in_squares_this_frame = _produce_list_centroids_this_frame( - list_indices_in_squares_this_frame, - relevant_particle_coordinate_array_xy, + list_centroids_in_squares_this_frame = ( + _produce_list_centroids_this_frame( + list_indices_in_squares_this_frame, + relevant_particle_coordinate_array_xy, + ) ) if ( list_previous_frame_indices @@ -281,7 +285,9 @@ def per_core_work( xy_deltas_to_write.append([0, 0]) else: xy_deltas_to_write.append( - np.subtract(square_1_centroid, square_2_centroid).tolist() + np.subtract( + square_1_centroid, square_2_centroid + ).tolist() ) # xy_deltas_to_write = np.subtract(np.array( @@ -297,11 +303,15 @@ def per_core_work( # with the xy and dx,dy values calculated I need to set the values from this frame to previous frame # values in anticipation of the next frame: - list_previous_frame_centroids = list_centroids_in_squares_this_frame[:] + list_previous_frame_centroids = ( + list_centroids_in_squares_this_frame[:] + ) list_previous_frame_indices = list_indices_in_squares_this_frame[:] else: # either no points in squares or after the first frame I'll just reset the 'previous' values so they # can be used when consecutive frames have proper values - list_previous_frame_centroids = list_centroids_in_squares_this_frame[:] + list_previous_frame_centroids = ( + list_centroids_in_squares_this_frame[:] + ) list_previous_frame_indices = list_indices_in_squares_this_frame[:] if ts.frame > end_frame: break # stop here @@ -417,7 +427,9 @@ def log_result_to_parent(delta_array): parent_list_deltas.extend(delta_array) tuple_of_limits = (xmin, xmax, ymin, ymax) - grid = produce_grid(tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing) + grid = produce_grid( + tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing + ) ( list_square_vertex_arrays_per_core, list_parent_index_values, diff --git a/package/MDAnalysis/visualization/streamlines_3D.py b/package/MDAnalysis/visualization/streamlines_3D.py index 5f00a288a7..4d2dace77b 100644 --- a/package/MDAnalysis/visualization/streamlines_3D.py +++ b/package/MDAnalysis/visualization/streamlines_3D.py @@ -56,7 +56,9 @@ import MDAnalysis -def determine_container_limits(topology_file_path, trajectory_file_path, buffer_value): +def determine_container_limits( + topology_file_path, trajectory_file_path, buffer_value +): """Calculate the extent of the atom coordinates + buffer. A function for the parent process which should take the input trajectory @@ -72,8 +74,12 @@ def determine_container_limits(topology_file_path, trajectory_file_path, buffer_ buffer_value : float buffer value (padding) in +/- {x, y, z} """ - universe_object = MDAnalysis.Universe(topology_file_path, trajectory_file_path) - all_atom_selection = universe_object.select_atoms("all") # select all particles + universe_object = MDAnalysis.Universe( + topology_file_path, trajectory_file_path + ) + all_atom_selection = universe_object.select_atoms( + "all" + ) # select all particles all_atom_coordinate_array = all_atom_selection.positions x_min, x_max, y_min, y_max, z_min, z_max = [ all_atom_coordinate_array[..., 0].min(), @@ -158,15 +164,21 @@ def split_grid(grid, num_cores): x ): # each x_sheet should have shape (25,23) and the same x value in each element array_all_x_values_current_sheet = x_sheet.flatten() - ordered_list_per_sheet_x_values.append(array_all_x_values_current_sheet) + ordered_list_per_sheet_x_values.append( + array_all_x_values_current_sheet + ) ordered_list_per_sheet_y_values = [] for y_columns in y: array_all_y_values_current_sheet = y_columns.flatten() - ordered_list_per_sheet_y_values.append(array_all_y_values_current_sheet) + ordered_list_per_sheet_y_values.append( + array_all_y_values_current_sheet + ) ordered_list_per_sheet_z_values = [] for z_slices in z: array_all_z_values_current_sheet = z_slices.flatten() - ordered_list_per_sheet_z_values.append(array_all_z_values_current_sheet) + ordered_list_per_sheet_z_values.append( + array_all_z_values_current_sheet + ) ordered_list_cartesian_coordinates_per_sheet = [] for x_sheet_coords, y_sheet_coords, z_sheet_coords in zip( @@ -209,11 +221,17 @@ def split_grid(grid, num_cores): current_index : current_index + 2, ... ].tolist() next_two_vertices_base_sheet = current_base_sheet_array[ - current_index + num_z_values : 2 + num_z_values + current_index, + current_index + + num_z_values : 2 + + num_z_values + + current_index, ..., ].tolist() next_two_vertices_top_sheet = current_top_sheet_array[ - current_index + num_z_values : 2 + num_z_values + current_index, + current_index + + num_z_values : 2 + + num_z_values + + current_index, ..., ].tolist() for vertex_set in [ @@ -228,7 +246,9 @@ def split_grid(grid, num_cores): 8, 3, ), "vertex_array has incorrect shape" - cube_centroid = np.average(np.array(current_list_cube_vertices), axis=0) + cube_centroid = np.average( + np.array(current_list_cube_vertices), axis=0 + ) dictionary_cubes_centroids_indices[cube_counter] = { "centroid": cube_centroid, "vertex_list": current_list_cube_vertices, @@ -246,7 +266,9 @@ def split_grid(grid, num_cores): # produce an array of pseudo cube indices (actually the dictionary keys which are cube numbers in string format): pseudo_cube_indices = np.arange(0, total_cubes) - sublist_of_cube_indices_per_core = np.array_split(pseudo_cube_indices, num_cores) + sublist_of_cube_indices_per_core = np.array_split( + pseudo_cube_indices, num_cores + ) # now, the split of pseudoindices seems to work well, and the above sublist_of_cube_indices_per_core is a list of # arrays of cube numbers / keys in the original dictionary # now I think I'll try to produce a list of dictionaries that each contain their assigned cubes based on the above @@ -287,16 +309,23 @@ def per_core_work( list_previous_frame_indices = [] # define some utility functions for trajectory iteration: - def point_in_cube(array_point_coordinates, list_cube_vertices, cube_centroid): + def point_in_cube( + array_point_coordinates, list_cube_vertices, cube_centroid + ): """Determine if an array of coordinates are within a cube.""" # the simulation particle point can't be more than half the cube side length away from the cube centroid in # any given dimension: array_cube_vertices = np.array(list_cube_vertices) cube_half_side_length = ( - scipy.spatial.distance.pdist(array_cube_vertices, "euclidean").min() / 2.0 + scipy.spatial.distance.pdist( + array_cube_vertices, "euclidean" + ).min() + / 2.0 ) - array_cube_vertex_distances_from_centroid = scipy.spatial.distance.cdist( - array_cube_vertices, cube_centroid[np.newaxis, :] + array_cube_vertex_distances_from_centroid = ( + scipy.spatial.distance.cdist( + array_cube_vertices, cube_centroid[np.newaxis, :] + ) ) np.testing.assert_allclose( array_cube_vertex_distances_from_centroid.min(), @@ -351,7 +380,9 @@ def update_dictionary_point_in_cube_start_frame( array_simulation_particle_coordinates[index_list_in_cube], axis=0, ) - cube["centroid_of_particles_first_frame"] = centroid_particles_in_cube + cube["centroid_of_particles_first_frame"] = ( + centroid_particles_in_cube + ) else: # empty cube cube["centroid_of_particles_first_frame"] = None cube_counter += 1 @@ -396,7 +427,9 @@ def update_dictionary_end_frame( update_dictionary_point_in_cube_start_frame( start_frame_coord_array, dictionary_cube_data_this_core ) - update_dictionary_end_frame(end_frame_coord_array, dictionary_cube_data_this_core) + update_dictionary_end_frame( + end_frame_coord_array, dictionary_cube_data_this_core + ) return dictionary_cube_data_this_core @@ -415,7 +448,9 @@ def produce_coordinate_arrays_single_process( waste memory. """ - universe_object = MDAnalysis.Universe(topology_file_path, trajectory_file_path) + universe_object = MDAnalysis.Universe( + topology_file_path, trajectory_file_path + ) relevant_particles = universe_object.select_atoms(MDA_selection) # pull out coordinate arrays from desired frames: for ts in universe_object.trajectory: @@ -570,7 +605,9 @@ def log_result_to_parent(process_dict): tuple_of_limits = (xmin, xmax, ymin, ymax, zmin, zmax) # step 2: produce a suitable grid (will assume that grid size / container size does not vary during simulation--or # at least not beyond the buffer limit, such that this grid can be used for all subsequent frames) - grid = produce_grid(tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing) + grid = produce_grid( + tuple_of_limits=tuple_of_limits, grid_spacing=grid_spacing + ) # step 3: split the grid into a dictionary of cube information that can be sent to each core for processing: list_dictionaries_for_cores, total_cubes, num_sheets, delta_array_shape = ( split_grid(grid=grid, num_cores=num_cores) @@ -618,15 +655,15 @@ def log_result_to_parent(process_dict): z_index_current_column = 0 # column total_cubes_current_sheet = 0 for cube_number in range(0, total_cubes): - dx_array[current_sheet, y_index_current_sheet, z_index_current_column] = ( - parent_cube_dictionary[cube_number]["dx"] - ) - dy_array[current_sheet, y_index_current_sheet, z_index_current_column] = ( - parent_cube_dictionary[cube_number]["dy"] - ) - dz_array[current_sheet, y_index_current_sheet, z_index_current_column] = ( - parent_cube_dictionary[cube_number]["dz"] - ) + dx_array[ + current_sheet, y_index_current_sheet, z_index_current_column + ] = parent_cube_dictionary[cube_number]["dx"] + dy_array[ + current_sheet, y_index_current_sheet, z_index_current_column + ] = parent_cube_dictionary[cube_number]["dy"] + dz_array[ + current_sheet, y_index_current_sheet, z_index_current_column + ] = parent_cube_dictionary[cube_number]["dz"] z_index_current_column += 1 total_cubes_current_sheet += 1 if z_index_current_column == delta_array_shape[2]: diff --git a/package/doc/sphinx/source/conf.py b/package/doc/sphinx/source/conf.py index d7a6ce5700..d1a288ed34 100644 --- a/package/doc/sphinx/source/conf.py +++ b/package/doc/sphinx/source/conf.py @@ -176,7 +176,9 @@ class KeyStyle(UnsrtStyle): # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_context = {"versions_json_url": "https://docs.mdanalysis.org/versions.json"} +html_context = { + "versions_json_url": "https://docs.mdanalysis.org/versions.json" +} # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". diff --git a/package/setup.py b/package/setup.py index 7f90d19c71..ff96377241 100755 --- a/package/setup.py +++ b/package/setup.py @@ -78,7 +78,9 @@ print( "Cython version {0} was found but won't be used: version {1} " "or greater is required because it offers a handy " - "parallelization module".format(Cython.__version__, required_version) + "parallelization module".format( + Cython.__version__, required_version + ) ) cython_found = False cython_linetrace = bool(os.environ.get("CYTHON_TRACE_NOGIL", False)) @@ -177,7 +179,9 @@ def get_numpy_include(): import numpy as np except ImportError: print('*** package "numpy" not found ***') - print("MDAnalysis requires a version of NumPy (>=1.21.0), even for setup.") + print( + "MDAnalysis requires a version of NumPy (>=1.21.0), even for setup." + ) print( "Please get it from http://numpy.scipy.org/ or install it through " "your package manager." @@ -452,10 +456,12 @@ def extensions(config): ap_clustering = MDAExtension( "MDAnalysis.analysis.encore.clustering.affinityprop", sources=[ - "MDAnalysis/analysis/encore/clustering/affinityprop" + source_suffix, + "MDAnalysis/analysis/encore/clustering/affinityprop" + + source_suffix, "MDAnalysis/analysis/encore/clustering/src/ap.c", ], - include_dirs=include_dirs + ["MDAnalysis/analysis/encore/clustering/include"], + include_dirs=include_dirs + + ["MDAnalysis/analysis/encore/clustering/include"], libraries=mathlib, define_macros=define_macros, extra_compile_args=encore_compile_args, @@ -599,7 +605,9 @@ def dynamic_author_list(): # Write the list of authors as a python list template = "__authors__ = [\n{}\n]" - author_string = ",\n".join(' u"{}"'.format(name) for name in authors) + author_string = ",\n".join( + ' u"{}"'.format(name) for name in authors + ) print(template.format(author_string), file=outfile) @@ -609,7 +617,9 @@ def long_description(readme): with open(abspath(readme)) as summary: buffer = summary.read() # remove top heading that messes up pypi display - m = re.search("====*\n[^\n]*README[^\n]*\n=====*\n", buffer, flags=re.DOTALL) + m = re.search( + "====*\n[^\n]*README[^\n]*\n=====*\n", buffer, flags=re.DOTALL + ) assert m, "README.rst does not contain a level-1 heading" return buffer[m.end() :] @@ -646,7 +656,10 @@ def long_description(readme): ) # Releases keep their cythonized stuff for shipping. - if not config.get("keep_cythonized", default=is_release) and not cython_linetrace: + if ( + not config.get("keep_cythonized", default=is_release) + and not cython_linetrace + ): for cythonized in cythonfiles: try: os.unlink(cythonized) diff --git a/testsuite/MDAnalysisTests/analysis/test_align.py b/testsuite/MDAnalysisTests/analysis/test_align.py index 37a5bccfea..fbda36b158 100644 --- a/testsuite/MDAnalysisTests/analysis/test_align.py +++ b/testsuite/MDAnalysisTests/analysis/test_align.py @@ -99,10 +99,14 @@ def reference(): @staticmethod @pytest.fixture() def reference_small(reference): - return mda.Merge(reference.select_atoms("not name H* and not atom 4AKE 1 CA")) + return mda.Merge( + reference.select_atoms("not name H* and not atom 4AKE 1 CA") + ) @pytest.mark.parametrize("strict", (True, False)) - def test_match(self, universe, reference, strict, selection="protein and backbone"): + def test_match( + self, universe, reference, strict, selection="protein and backbone" + ): ref = reference.select_atoms(selection) mobile = universe.select_atoms(selection) groups = align.get_matching_atoms(ref, mobile, strict=strict) @@ -122,7 +126,9 @@ def test_nomatch_atoms_raise( else: with pytest.warns(SelectionWarning): with pytest.raises(SelectionError): - groups = align.get_matching_atoms(ref, mobile, strict=strict) + groups = align.get_matching_atoms( + ref, mobile, strict=strict + ) @pytest.mark.parametrize("strict", (True, False)) def test_nomatch_residues_raise_empty( @@ -143,7 +149,9 @@ def test_nomatch_residues_raise_empty( else: with pytest.warns(SelectionWarning): with pytest.raises(SelectionError): - groups = align.get_matching_atoms(ref, mobile, strict=strict) + groups = align.get_matching_atoms( + ref, mobile, strict=strict + ) def test_toggle_atom_mismatch_default_error(self, universe, reference): selection = ("resname ALA and name CA", "resname ALA and name O") @@ -159,7 +167,9 @@ def test_toggle_atom_mismatch_kwarg_error(self, universe, reference): def test_toggle_atom_nomatch(self, universe, reference): selection = ("resname ALA and name CA", "resname ALA and name O") - rmsd = align.alignto(universe, reference, select=selection, match_atoms=False) + rmsd = align.alignto( + universe, reference, select=selection, match_atoms=False + ) assert rmsd[0] > 0.01 def test_toggle_atom_nomatch_mismatch_atoms(self, universe, reference): @@ -181,20 +191,28 @@ def test_toggle_atom_nomatch_mismatch_atoms(self, universe, reference): (1234, pytest.raises(TypeError)), ], ) - def test_subselection_alignto(self, universe, reference, subselection, expectation): + def test_subselection_alignto( + self, universe, reference, subselection, expectation + ): with expectation: - rmsd = align.alignto(universe, reference, subselection=subselection) + rmsd = align.alignto( + universe, reference, subselection=subselection + ) assert_allclose(rmsd[1], 0.0, rtol=0, atol=1.5e-9) def test_no_atom_masses(self, universe): # if no masses are present - u = mda.Universe.empty(6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True) + u = mda.Universe.empty( + 6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True + ) with pytest.warns(SelectionWarning): align.get_matching_atoms(u.atoms, u.atoms) def test_one_universe_has_masses(self, universe): - u = mda.Universe.empty(6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True) + u = mda.Universe.empty( + 6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True + ) ref = mda.Universe.empty( 6, 2, atom_resindex=[0, 0, 0, 1, 1, 1], trajectory=True ) @@ -259,7 +277,9 @@ def test_rmsd_custom_mass_weights(self, universe, reference): last_atoms_weight = universe.atoms.masses A = universe.trajectory[0] B = reference.trajectory[-1] - rmsd = align.alignto(universe, reference, weights=reference.atoms.masses) + rmsd = align.alignto( + universe, reference, weights=reference.atoms.masses + ) rmsd_sup_weight = rms.rmsd( A, B, weights=last_atoms_weight, center=True, superposition=True ) @@ -282,7 +302,9 @@ def test_AlignTraj_outfile_default(self, universe, reference, tmpdir): finally: x._writer.close() - def test_AlignTraj_outfile_default_exists(self, universe, reference, tmpdir): + def test_AlignTraj_outfile_default_exists( + self, universe, reference, tmpdir + ): reference.trajectory[-1] outfile = str(tmpdir.join("align_test.dcd")) align.AlignTraj(universe, reference, filename=outfile).run() @@ -334,12 +356,16 @@ def test_AlignTraj(self, universe, reference, tmpdir): def test_AlignTraj_weighted(self, universe, reference, tmpdir): outfile = str(tmpdir.join("align_test.dcd")) - x = align.AlignTraj(universe, reference, filename=outfile, weights="mass").run() + x = align.AlignTraj( + universe, reference, filename=outfile, weights="mass" + ).run() fitted = mda.Universe(PSF, outfile) assert_allclose(x.results.rmsd[0], 0, rtol=0, atol=1.5e-3) assert_allclose(x.results.rmsd[-1], 6.9033, rtol=0, atol=1.5e-3) - self._assert_rmsd(reference, fitted, 0, 0.0, weights=universe.atoms.masses) + self._assert_rmsd( + reference, fitted, 0, 0.0, weights=universe.atoms.masses + ) self._assert_rmsd( reference, fitted, @@ -362,7 +388,9 @@ def test_AlignTraj_custom_weights(self, universe, reference, tmpdir): universe, reference, filename=outfile, weights=weights ).run() - assert_allclose(x.results.rmsd, x_weights.results.rmsd, rtol=0, atol=1.5e-7) + assert_allclose( + x.results.rmsd, x_weights.results.rmsd, rtol=0, atol=1.5e-7 + ) def test_AlignTraj_custom_mass_weights(self, universe, reference, tmpdir): outfile = str(tmpdir.join("align_test.dcd")) @@ -376,7 +404,9 @@ def test_AlignTraj_custom_mass_weights(self, universe, reference, tmpdir): assert_allclose(x.results.rmsd[0], 0, rtol=0, atol=1.5e-3) assert_allclose(x.results.rmsd[-1], 6.9033, rtol=0, atol=1.5e-3) - self._assert_rmsd(reference, fitted, 0, 0.0, weights=universe.atoms.masses) + self._assert_rmsd( + reference, fitted, 0, 0.0, weights=universe.atoms.masses + ) self._assert_rmsd( reference, fitted, @@ -400,7 +430,9 @@ def test_AlignTraj_partial_fit(self, universe, reference, tmpdir): def test_AlignTraj_in_memory(self, universe, reference, tmpdir): outfile = str(tmpdir.join("align_test.dcd")) reference.trajectory[-1] - x = align.AlignTraj(universe, reference, filename=outfile, in_memory=True).run() + x = align.AlignTraj( + universe, reference, filename=outfile, in_memory=True + ).run() assert x.filename is None assert_allclose(x.results.rmsd[0], 6.9290, rtol=0, atol=1.5e-3) assert_allclose(x.results.rmsd[-1], 5.2797e-07, rtol=0, atol=1.5e-3) @@ -435,7 +467,8 @@ def _assert_rmsd(self, reference, fitted, frame, desired, weights=None): desired, rtol=0, atol=1.5e-5, - err_msg="frame {0:d} of fit does not have " "expected RMSD".format(frame), + err_msg="frame {0:d} of fit does not have " + "expected RMSD".format(frame), ) def test_alignto_checks_selections(self, universe, reference): @@ -469,7 +502,9 @@ def test_alignto_partial_universe(self, universe, reference): segB_free.translate(segB_bound.centroid() - segB_free.centroid()) align.alignto(u_free, u_bound, select=selection) - assert_allclose(segB_bound.positions, segB_free.positions, rtol=0, atol=1.5e-3) + assert_allclose( + segB_bound.positions, segB_free.positions, rtol=0, atol=1.5e-3 + ) def _get_aligned_average_positions(ref_files, ref, select="all", **kwargs): @@ -515,7 +550,9 @@ def test_average_structure_deprecated_attrs(self, universe, reference): def test_average_structure(self, universe, reference): ref, rmsd = _get_aligned_average_positions(self.ref_files, reference) avg = align.AverageStructure(universe, reference).run() - assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) + assert_allclose( + avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 + ) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_mass_weighted(self, universe, reference): @@ -523,7 +560,9 @@ def test_average_structure_mass_weighted(self, universe, reference): self.ref_files, reference, weights="mass" ) avg = align.AverageStructure(universe, reference, weights="mass").run() - assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) + assert_allclose( + avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 + ) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_select(self, universe, reference): @@ -532,13 +571,17 @@ def test_average_structure_select(self, universe, reference): self.ref_files, reference, select=select ) avg = align.AverageStructure(universe, reference, select=select).run() - assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) + assert_allclose( + avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 + ) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_no_ref(self, universe): ref, rmsd = _get_aligned_average_positions(self.ref_files, universe) avg = align.AverageStructure(universe).run() - assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) + assert_allclose( + avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 + ) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_no_msf(self, universe): @@ -562,7 +605,9 @@ def test_average_structure_ref_frame(self, universe): universe.trajectory[0] ref, rmsd = _get_aligned_average_positions(self.ref_files, u) avg = align.AverageStructure(universe, ref_frame=ref_frame).run() - assert_allclose(avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4) + assert_allclose( + avg.results.universe.atoms.positions, ref, rtol=0, atol=1.5e-4 + ) assert_allclose(avg.results.rmsd, rmsd, rtol=0, atol=1.5e-7) def test_average_structure_in_memory(self, universe): diff --git a/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py b/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py index 9e8341bf7d..4697485470 100644 --- a/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py +++ b/testsuite/MDAnalysisTests/analysis/test_atomicdistances.py @@ -79,7 +79,9 @@ def ad_ag4(): @staticmethod @pytest.fixture() def expected_dist(ad_ag1, ad_ag2): - expected = np.zeros((len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms)) + expected = np.zeros( + (len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms) + ) # calculate distances without PBCs using dist() for i, ts in enumerate(ad_ag1.universe.trajectory): @@ -89,7 +91,9 @@ def expected_dist(ad_ag1, ad_ag2): @staticmethod @pytest.fixture() def expected_pbc_dist(ad_ag1, ad_ag2): - expected = np.zeros((len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms)) + expected = np.zeros( + (len(ad_ag1.universe.trajectory), ad_ag1.atoms.n_atoms) + ) # calculate distances with PBCs using dist() for i, ts in enumerate(ad_ag1.universe.trajectory): diff --git a/testsuite/MDAnalysisTests/analysis/test_base.py b/testsuite/MDAnalysisTests/analysis/test_base.py index eada555174..0dd872bde5 100644 --- a/testsuite/MDAnalysisTests/analysis/test_base.py +++ b/testsuite/MDAnalysisTests/analysis/test_base.py @@ -56,7 +56,9 @@ def _conclude(self): self.found_frames = list(self.results.found_frames) def _get_aggregator(self): - return base.ResultsGroup({"found_frames": base.ResultsGroup.ndarray_hstack}) + return base.ResultsGroup( + {"found_frames": base.ResultsGroup.ndarray_hstack} + ) class IncompleteAnalysis(base.AnalysisBase): @@ -171,7 +173,9 @@ def test_n_workers_conflict_raises_value_error(u): def test_backend_configuration_fails(u, run_class, backend, n_workers): u = mda.Universe(TPR, XTC) # dt = 100 with pytest.raises(ValueError): - _ = run_class(u.trajectory).run(backend=backend, n_workers=n_workers, stop=0) + _ = run_class(u.trajectory).run( + backend=backend, n_workers=n_workers, stop=0 + ) @pytest.mark.parametrize( @@ -217,7 +221,9 @@ def test_custom_backend_works(u, run_class, backend, n_workers): (ParallelizableWithDaskOnly, object, 1), ], ) -def test_fails_incorrect_custom_backend(u, run_class, backend_instance, n_workers): +def test_fails_incorrect_custom_backend( + u, run_class, backend_instance, n_workers +): u = mda.Universe(TPR, XTC) # dt = 100 with pytest.raises(ValueError): _ = run_class(u.trajectory).run( @@ -227,7 +233,9 @@ def test_fails_incorrect_custom_backend(u, run_class, backend_instance, n_worker ) with pytest.raises(ValueError): - _ = run_class(u.trajectory).run(backend=backend_instance, n_workers=n_workers) + _ = run_class(u.trajectory).run( + backend=backend_instance, n_workers=n_workers + ) @pytest.mark.parametrize( @@ -281,7 +289,9 @@ def test_reset_n_parts_to_n_frames(u): """ a = FrameAnalysis(u.trajectory) with pytest.warns(UserWarning, match="Set `n_parts` to"): - a.run(backend="multiprocessing", start=0, stop=1, n_workers=2, n_parts=2) + a.run( + backend="multiprocessing", start=0, stop=1, n_workers=2, n_parts=2 + ) @pytest.mark.parametrize( @@ -298,7 +308,9 @@ def test_start_stop_step(u, run_kwargs, frames): assert an.n_frames == len(frames) assert_equal(an.found_frames, frames) assert_equal(an.frames, frames, err_msg=FRAMES_ERR) - assert_allclose(an.times, frames + 1, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR) + assert_allclose( + an.times, frames + 1, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR + ) @pytest.mark.parametrize( @@ -426,7 +438,9 @@ def test_frame_bool_fail(client_FrameAnalysis): def test_rewind(client_FrameAnalysis): u = mda.Universe(TPR, XTC) # dt = 100 - an = FrameAnalysis(u.trajectory).run(**client_FrameAnalysis, frames=[0, 2, 3, 5, 9]) + an = FrameAnalysis(u.trajectory).run( + **client_FrameAnalysis, frames=[0, 2, 3, 5, 9] + ) assert_equal(u.trajectory.ts.frame, 0) @@ -439,7 +453,9 @@ def test_frames_times(client_FrameAnalysis): assert an.n_frames == len(frames) assert_equal(an.found_frames, frames) assert_equal(an.frames, frames, err_msg=FRAMES_ERR) - assert_allclose(an.times, frames * 100, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR) + assert_allclose( + an.times, frames * 100, rtol=0, atol=1.5e-4, err_msg=TIMES_ERR + ) def test_verbose(u): @@ -482,7 +498,9 @@ def test_verbose_progressbar_run(u, capsys): def test_verbose_progressbar_run_with_kwargs(u, capsys): - FrameAnalysis(u.trajectory).run(verbose=True, progressbar_kwargs={"desc": "custom"}) + FrameAnalysis(u.trajectory).run( + verbose=True, progressbar_kwargs={"desc": "custom"} + ) _, err = capsys.readouterr() expected = "custom: 100%|██████████" actual = err.strip().split("\r")[-1] @@ -491,7 +509,9 @@ def test_verbose_progressbar_run_with_kwargs(u, capsys): def test_progressbar_multiprocessing(u): with pytest.raises(ValueError): - FrameAnalysis(u.trajectory).run(backend="multiprocessing", verbose=True) + FrameAnalysis(u.trajectory).run( + backend="multiprocessing", verbose=True + ) def test_incomplete_defined_analysis(u): @@ -606,7 +626,9 @@ def test_analysis_class(client_AnalysisFromFunctionAnalysisClass): u = mda.Universe(PSF, DCD) step = 2 - ana = ana_class(u.atoms).run(step=step, **client_AnalysisFromFunctionAnalysisClass) + ana = ana_class(u.atoms).run( + step=step, **client_AnalysisFromFunctionAnalysisClass + ) results = [] for ts in u.trajectory[::step]: diff --git a/testsuite/MDAnalysisTests/analysis/test_bat.py b/testsuite/MDAnalysisTests/analysis/test_bat.py index 91c040646a..704cf616cb 100644 --- a/testsuite/MDAnalysisTests/analysis/test_bat.py +++ b/testsuite/MDAnalysisTests/analysis/test_bat.py @@ -70,7 +70,9 @@ def test_bat_root_selection(self, selected_residues): ) def test_bat_number_of_frames(self, bat): - assert_equal(len(bat), 2, err_msg="error: list is not length of trajectory") + assert_equal( + len(bat), 2, err_msg="error: list is not length of trajectory" + ) def test_bat_coordinates(self, bat): test_bat = np.load(BATArray) @@ -83,7 +85,11 @@ def test_bat_coordinates(self, bat): ) def test_bat_coordinates_single_frame(self, selected_residues, client_BAT): - bat = BAT(selected_residues).run(start=1, stop=2, **client_BAT).results.bat + bat = ( + BAT(selected_residues) + .run(start=1, stop=2, **client_BAT) + .results.bat + ) test_bat = [np.load(BATArray)[1]] assert_allclose( bat, @@ -129,7 +135,9 @@ def test_bat_bad_initial_atom(self, selected_residues): def test_bat_disconnected_atom_group(self): u = mda.Universe(PSF, DCD) - selected_residues = u.select_atoms("resid 1-3") + u.select_atoms("resid 5-7") + selected_residues = u.select_atoms("resid 1-3") + u.select_atoms( + "resid 5-7" + ) errmsg = "Additional torsions not found." with pytest.raises(ValueError, match=errmsg): R = BAT(selected_residues) diff --git a/testsuite/MDAnalysisTests/analysis/test_contacts.py b/testsuite/MDAnalysisTests/analysis/test_contacts.py index 7868acc5e9..7f4a5b69ec 100644 --- a/testsuite/MDAnalysisTests/analysis/test_contacts.py +++ b/testsuite/MDAnalysisTests/analysis/test_contacts.py @@ -206,7 +206,9 @@ def test_contacts_selections(self, universe, client_Contacts): aga = universe.select_atoms(self.sel_acidic) agb = universe.select_atoms(self.sel_basic) - cag = contacts.Contacts(universe, select=(aga, agb), refgroup=(aga, agb)) + cag = contacts.Contacts( + universe, select=(aga, agb), refgroup=(aga, agb) + ) csel = contacts.Contacts( universe, @@ -242,7 +244,9 @@ def test_startframe(self, universe, client_Contacts): def test_end_zero(self, universe, client_Contacts): """test_end_zero: TestContactAnalysis1: stop frame 0 is not ignored""" - CA1 = self._run_Contacts(universe, client_Contacts=client_Contacts, stop=0) + CA1 = self._run_Contacts( + universe, client_Contacts=client_Contacts, stop=0 + ) assert len(CA1.results.timeseries) == 0 def test_slicing(self, universe, client_Contacts): @@ -271,7 +275,9 @@ def test_villin_folded(self, client_Contacts): q.run(**client_Contacts) results = soft_cut(f, u, sel, sel) - assert_allclose(q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7) + assert_allclose( + q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7 + ) def test_villin_unfolded(self, client_Contacts): # both folded @@ -287,7 +293,9 @@ def test_villin_unfolded(self, client_Contacts): q.run(**client_Contacts) results = soft_cut(f, u, sel, sel) - assert_allclose(q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7) + assert_allclose( + q.results.timeseries[:, 1], results[:, 1], rtol=0, atol=1.5e-7 + ) def test_hard_cut_method(self, universe, client_Contacts): ca = self._run_Contacts(universe, client_Contacts=client_Contacts) @@ -316,7 +324,9 @@ def test_hard_cut_method(self, universe, client_Contacts): ] # fmt: on assert len(ca.results.timeseries) == len(expected) - assert_allclose(ca.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7) + assert_allclose( + ca.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7 + ) def test_radius_cut_method(self, universe, client_Contacts): acidic = universe.select_atoms(self.sel_acidic) @@ -428,12 +438,16 @@ def test_distance_box(self, pbc, expected, client_Contacts): pbc=pbc, ) r.run(**client_Contacts) - assert_allclose(r.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7) + assert_allclose( + r.results.timeseries[:, 1], expected, rtol=0, atol=1.5e-7 + ) def test_warn_deprecated_attr(self, universe, client_Contacts): """Test for warning message emitted on using deprecated `timeseries` attribute""" - CA1 = self._run_Contacts(universe, client_Contacts=client_Contacts, stop=1) + CA1 = self._run_Contacts( + universe, client_Contacts=client_Contacts, stop=1 + ) wmsg = "The `timeseries` attribute was deprecated in MDAnalysis" with pytest.warns(DeprecationWarning, match=wmsg): assert_equal(CA1.timeseries, CA1.results.timeseries) @@ -480,7 +494,9 @@ def test_q1q2(client_Contacts): 0.93006358, 0.9346049, 0.93188011, ] # fmt: on - assert_allclose(q1q2.results.timeseries[:, 1], q1_expected, rtol=0, atol=1.5e-7) + assert_allclose( + q1q2.results.timeseries[:, 1], q1_expected, rtol=0, atol=1.5e-7 + ) # fmt: off q2_expected = [ @@ -506,4 +522,6 @@ def test_q1q2(client_Contacts): 0.98616236, 0.9898524, 1.0, ] # fmt: on - assert_allclose(q1q2.results.timeseries[:, 2], q2_expected, rtol=0, atol=1.5e-7) + assert_allclose( + q1q2.results.timeseries[:, 2], q2_expected, rtol=0, atol=1.5e-7 + ) diff --git a/testsuite/MDAnalysisTests/analysis/test_density.py b/testsuite/MDAnalysisTests/analysis/test_density.py index 7511f997a3..3547ff9fe9 100644 --- a/testsuite/MDAnalysisTests/analysis/test_density.py +++ b/testsuite/MDAnalysisTests/analysis/test_density.py @@ -51,7 +51,9 @@ def bins(self): def h_and_edges(self, bins): return np.histogramdd( self.Lmax - * np.sin(np.linspace(0, 1, self.counts * 3)).reshape(self.counts, 3), + * np.sin(np.linspace(0, 1, self.counts * 3)).reshape( + self.counts, 3 + ), bins=bins, ) @@ -239,7 +241,9 @@ class DensityParameters(object): @pytest.fixture() def universe(self): - return mda.Universe(self.topology, self.trajectory, tpr_resid_from_one=False) + return mda.Universe( + self.topology, self.trajectory, tpr_resid_from_one=False + ) class TestDensityAnalysis(DensityParameters): @@ -365,7 +369,9 @@ def test_ValueError_userdefn_gridcenter_shape( self, universe, client_DensityAnalysis ): # Test len(gridcenter) != 3 - with pytest.raises(ValueError, match="Gridcenter must be a 3D coordinate"): + with pytest.raises( + ValueError, match="Gridcenter must be a 3D coordinate" + ): D = density.DensityAnalysis( universe.select_atoms(self.selections["static"]), delta=self.delta, @@ -379,7 +385,9 @@ def test_ValueError_userdefn_gridcenter_type( self, universe, client_DensityAnalysis ): # Test gridcenter includes non-numeric strings - with pytest.raises(ValueError, match="Gridcenter must be a 3D coordinate"): + with pytest.raises( + ValueError, match="Gridcenter must be a 3D coordinate" + ): D = density.DensityAnalysis( universe.select_atoms(self.selections["static"]), delta=self.delta, @@ -403,9 +411,13 @@ def test_ValueError_userdefn_gridcenter_missing( zdim=10.0, ).run(step=5, **client_DensityAnalysis) - def test_ValueError_userdefn_xdim_type(self, universe, client_DensityAnalysis): + def test_ValueError_userdefn_xdim_type( + self, universe, client_DensityAnalysis + ): # Test xdim != int or float - with pytest.raises(ValueError, match="xdim, ydim, and zdim must be numbers"): + with pytest.raises( + ValueError, match="xdim, ydim, and zdim must be numbers" + ): D = density.DensityAnalysis( universe.select_atoms(self.selections["static"]), delta=self.delta, @@ -415,7 +427,9 @@ def test_ValueError_userdefn_xdim_type(self, universe, client_DensityAnalysis): gridcenter=self.gridcenters["static_defined"], ).run(step=5, **client_DensityAnalysis) - def test_ValueError_userdefn_xdim_nanvalue(self, universe, client_DensityAnalysis): + def test_ValueError_userdefn_xdim_nanvalue( + self, universe, client_DensityAnalysis + ): # Test xdim set to NaN value regex = "Gridcenter or grid dimensions have NaN element" with pytest.raises(ValueError, match=regex): @@ -462,7 +476,9 @@ def test_ValueError_noatomgroup(self, universe, client_DensityAnalysis): ).run(step=5, **client_DensityAnalysis) def test_warn_results_deprecated(self, universe, client_DensityAnalysis): - D = density.DensityAnalysis(universe.select_atoms(self.selections["static"])) + D = density.DensityAnalysis( + universe.select_atoms(self.selections["static"]) + ) D.run(stop=1, **client_DensityAnalysis) wmsg = "The `density` attribute was deprecated in MDAnalysis 2.0.0" with pytest.warns(DeprecationWarning, match=wmsg): diff --git a/testsuite/MDAnalysisTests/analysis/test_dielectric.py b/testsuite/MDAnalysisTests/analysis/test_dielectric.py index ba19e40780..45d8e722cd 100644 --- a/testsuite/MDAnalysisTests/analysis/test_dielectric.py +++ b/testsuite/MDAnalysisTests/analysis/test_dielectric.py @@ -58,7 +58,9 @@ def test_temperature(self, ag): def test_non_charges(self): u = mda.Universe(DCD_TRICLINIC, to_guess=()) - with pytest.raises(NoDataError, match="No charges defined given atomgroup."): + with pytest.raises( + NoDataError, match="No charges defined given atomgroup." + ): DielectricConstant(u.atoms).run() def test_non_neutral(self, ag): diff --git a/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py b/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py index b8c1265d8f..99e978b3ff 100644 --- a/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py +++ b/testsuite/MDAnalysisTests/analysis/test_diffusionmap.py @@ -55,7 +55,9 @@ def test_eg(dist, dmap): def test_dist_weights(u): backbone = u.select_atoms("backbone") weights_atoms = np.ones(len(backbone.atoms)) - dist = diffusionmap.DistanceMatrix(u, select="backbone", weights=weights_atoms) + dist = diffusionmap.DistanceMatrix( + u, select="backbone", weights=weights_atoms + ) dist.run(step=3) dmap = diffusionmap.DiffusionMap(dist) dmap.run() @@ -77,7 +79,9 @@ def test_dist_weights(u): def test_dist_weights_frames(u): backbone = u.select_atoms("backbone") weights_atoms = np.ones(len(backbone.atoms)) - dist = diffusionmap.DistanceMatrix(u, select="backbone", weights=weights_atoms) + dist = diffusionmap.DistanceMatrix( + u, select="backbone", weights=weights_atoms + ) frames = np.arange(len(u.trajectory)) dist.run(frames=frames[::3]) dmap = diffusionmap.DiffusionMap(dist) @@ -101,14 +105,18 @@ def test_distvalues_ag_universe(u): dist_universe = diffusionmap.DistanceMatrix(u, select="backbone").run() ag = u.select_atoms("backbone") dist_ag = diffusionmap.DistanceMatrix(ag).run() - assert_allclose(dist_universe.results.dist_matrix, dist_ag.results.dist_matrix) + assert_allclose( + dist_universe.results.dist_matrix, dist_ag.results.dist_matrix + ) def test_distvalues_ag_select(u): dist_universe = diffusionmap.DistanceMatrix(u, select="backbone").run() ag = u.select_atoms("protein") dist_ag = diffusionmap.DistanceMatrix(ag, select="backbone").run() - assert_allclose(dist_universe.results.dist_matrix, dist_ag.results.dist_matrix) + assert_allclose( + dist_universe.results.dist_matrix, dist_ag.results.dist_matrix + ) def test_different_steps(u): diff --git a/testsuite/MDAnalysisTests/analysis/test_dihedrals.py b/testsuite/MDAnalysisTests/analysis/test_dihedrals.py index 62efb550b5..82625dfb93 100644 --- a/testsuite/MDAnalysisTests/analysis/test_dihedrals.py +++ b/testsuite/MDAnalysisTests/analysis/test_dihedrals.py @@ -48,7 +48,9 @@ class TestDihedral(object): @pytest.fixture() def atomgroup(self): u = mda.Universe(GRO, XTC) - ag = u.select_atoms("(resid 4 and name N CA C) or (resid 5 and name N)") + ag = u.select_atoms( + "(resid 4 and name N CA C) or (resid 5 and name N)" + ) return ag def test_dihedral(self, atomgroup, client_Dihedral): @@ -70,7 +72,9 @@ def test_dihedral(self, atomgroup, client_Dihedral): ) def test_dihedral_single_frame(self, atomgroup, client_Dihedral): - dihedral = Dihedral([atomgroup]).run(start=5, stop=6, **client_Dihedral) + dihedral = Dihedral([atomgroup]).run( + start=5, stop=6, **client_Dihedral + ) test_dihedral = [np.load(DihedralArray)[5]] assert_allclose( @@ -116,7 +120,9 @@ def rama_ref_array(self): return np.load(RamaArray) def test_ramachandran(self, universe, rama_ref_array, client_Ramachandran): - rama = Ramachandran(universe.select_atoms("protein")).run(**client_Ramachandran) + rama = Ramachandran(universe.select_atoms("protein")).run( + **client_Ramachandran + ) assert_allclose( rama.results.angles, @@ -141,7 +147,9 @@ def test_ramachandran_single_frame( err_msg="error: dihedral angles should " "match test values", ) - def test_ramachandran_residue_selections(self, universe, client_Ramachandran): + def test_ramachandran_residue_selections( + self, universe, client_Ramachandran + ): rama = Ramachandran(universe.select_atoms("resname GLY")).run( **client_Ramachandran ) @@ -179,7 +187,11 @@ def test_None_removal(self): rama = Ramachandran(u.select_atoms("protein").residues[1:-1]) def test_plot(self, universe): - ax = Ramachandran(universe.select_atoms("resid 5-10")).run().plot(ref=True) + ax = ( + Ramachandran(universe.select_atoms("resid 5-10")) + .run() + .plot(ref=True) + ) assert isinstance( ax, matplotlib.axes.Axes ), "Ramachandran.plot() did not return and Axes instance" @@ -260,7 +272,9 @@ def test_atom_selection(self): with pytest.raises(ValueError): u = mda.Universe(PDB_janin) janin = Janin( - u.select_atoms("protein and not resname ALA CYS GLY " "PRO SER THR VAL") + u.select_atoms( + "protein and not resname ALA CYS GLY " "PRO SER THR VAL" + ) ) def test_plot(self, universe): diff --git a/testsuite/MDAnalysisTests/analysis/test_distances.py b/testsuite/MDAnalysisTests/analysis/test_distances.py index 0a466b1ab4..90fe8d75e8 100644 --- a/testsuite/MDAnalysisTests/analysis/test_distances.py +++ b/testsuite/MDAnalysisTests/analysis/test_distances.py @@ -96,28 +96,36 @@ def test_np(self, coord, shape, res_no_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, cutoff=1, returntype="numpy" ) - assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) + assert contacts.shape == shape, "wrong shape (should be {0})".format( + shape + ) assert_equal(contacts, res_no_pbc) def test_sparse(self, coord, shape, res_no_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, cutoff=1.5, returntype="sparse" ) - assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) + assert contacts.shape == shape, "wrong shape (should be {0})".format( + shape + ) assert_equal(contacts.toarray(), res_no_pbc) def test_box_numpy(self, coord, box, shape, res_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, box=box, cutoff=1 ) - assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) + assert contacts.shape == shape, "wrong shape (should be {0})".format( + shape + ) assert_equal(contacts, res_pbc) def test_box_sparse(self, coord, box, shape, res_pbc): contacts = MDAnalysis.analysis.distances.contact_matrix( coord, box=box, cutoff=1, returntype="sparse" ) - assert contacts.shape == shape, "wrong shape (should be {0})".format(shape) + assert contacts.shape == shape, "wrong shape (should be {0})".format( + shape + ) assert_equal(contacts.toarray(), res_pbc) @@ -145,7 +153,9 @@ def box(): @pytest.fixture() def expected(ag, ag2): - return np.diag(scipy.spatial.distance.cdist(ag.positions, ag2.positions)) + return np.diag( + scipy.spatial.distance.cdist(ag.positions, ag2.positions) + ) @staticmethod @pytest.fixture() @@ -177,7 +187,9 @@ def test_pairwise_dist_offset_effect(self, ag, ag2, expected): def test_offset_calculation(self, ag, ag2): """Test that offsets fed to dist() are correctly calculated.""" actual = MDAnalysis.analysis.distances.dist(ag, ag2, offset=33)[:2] - assert_equal(actual, np.array([ag.atoms.resids + 33, ag2.atoms.resids + 33])) + assert_equal( + actual, np.array([ag.atoms.resids + 33, ag2.atoms.resids + 33]) + ) def test_mismatch_exception(self, ag, ag2, expected): """A ValueError should be raised if the two atomgroups @@ -211,7 +223,9 @@ def group(u): @pytest.fixture() def expected(self, group, ag, ag2): - distance_matrix_1 = scipy.spatial.distance.cdist(group.positions, ag.positions) + distance_matrix_1 = scipy.spatial.distance.cdist( + group.positions, ag.positions + ) mask_1 = np.unique(np.where(distance_matrix_1 <= self.distance)[0]) group_filtered = group[mask_1] distance_matrix_2 = scipy.spatial.distance.cdist( diff --git a/testsuite/MDAnalysisTests/analysis/test_dssp.py b/testsuite/MDAnalysisTests/analysis/test_dssp.py index 7b132d0032..ee43a400df 100644 --- a/testsuite/MDAnalysisTests/analysis/test_dssp.py +++ b/testsuite/MDAnalysisTests/analysis/test_dssp.py @@ -9,7 +9,9 @@ # Files that match glob pattern '????.pdb.gz' and matching '????.pdb.dssp' files, # containing the secondary structure assignment string, will be tested automatically. -@pytest.mark.parametrize("pdb_filename", glob.glob(f"{DSSP_FOLDER}/?????.pdb.gz")) +@pytest.mark.parametrize( + "pdb_filename", glob.glob(f"{DSSP_FOLDER}/?????.pdb.gz") +) def test_file_guess_hydrogens(pdb_filename, client_DSSP): u = mda.Universe(pdb_filename) with open(f"{pdb_filename.rstrip('.gz')}.dssp", "r") as fin: @@ -27,7 +29,9 @@ def test_trajectory(client_DSSP): last_frame = "".join(run.results.dssp[-1]) avg_frame = "".join(translate(run.results.dssp_ndarray.mean(axis=0))) - assert first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" + assert ( + first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" + ) protein = mda.Universe(TPR, XTC).select_atoms("protein") run = DSSP(protein).run(**client_DSSP, stop=10) @@ -39,7 +43,9 @@ def test_atomgroup(client_DSSP): last_frame = "".join(run.results.dssp[-1]) avg_frame = "".join(translate(run.results.dssp_ndarray.mean(axis=0))) - assert first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" + assert ( + first_frame[:10] != last_frame[:10] == avg_frame[:10] == "-EEEEEE---" + ) def test_trajectory_with_hydrogens(client_DSSP): @@ -49,10 +55,14 @@ def test_trajectory_with_hydrogens(client_DSSP): last_frame = "".join(run.results.dssp[-1]) avg_frame = "".join(translate(run.results.dssp_ndarray.mean(axis=0))) - assert first_frame[:10] == last_frame[:10] == avg_frame[:10] == "-EEEEEE---" + assert ( + first_frame[:10] == last_frame[:10] == avg_frame[:10] == "-EEEEEE---" + ) -@pytest.mark.parametrize("pdb_filename", glob.glob(f"{DSSP_FOLDER}/2xdgA.pdb.gz")) +@pytest.mark.parametrize( + "pdb_filename", glob.glob(f"{DSSP_FOLDER}/2xdgA.pdb.gz") +) def test_trajectory_without_hydrogen_fails(pdb_filename, client_DSSP): u = mda.Universe(pdb_filename) with pytest.raises(ValueError): @@ -62,7 +72,9 @@ def test_trajectory_without_hydrogen_fails(pdb_filename, client_DSSP): @pytest.mark.parametrize( "pdb_filename", glob.glob(f"{DSSP_FOLDER}/1mr1D_failing.pdb.gz") ) -def test_trajectory_with_uneven_number_of_atoms_fails(pdb_filename, client_DSSP): +def test_trajectory_with_uneven_number_of_atoms_fails( + pdb_filename, client_DSSP +): u = mda.Universe(pdb_filename) with pytest.raises(ValueError): DSSP(u, guess_hydrogens=True).run(**client_DSSP) diff --git a/testsuite/MDAnalysisTests/analysis/test_encore.py b/testsuite/MDAnalysisTests/analysis/test_encore.py index ee2d493bc0..9204352f48 100644 --- a/testsuite/MDAnalysisTests/analysis/test_encore.py +++ b/testsuite/MDAnalysisTests/analysis/test_encore.py @@ -90,7 +90,9 @@ def test_triangular_matrix(self): triangular_matrix[0, 1] = expected_value - err_msg = "Data error in TriangularMatrix: read/write are not consistent" + err_msg = ( + "Data error in TriangularMatrix: read/write are not consistent" + ) assert_equal(triangular_matrix[0, 1], expected_value, err_msg) assert_equal( @@ -167,18 +169,23 @@ def test_parallel_calculation(self): ) def test_rmsd_matrix_with_superimposition(self, ens1): - conf_dist_matrix = encore.confdistmatrix.conformational_distance_matrix( - ens1, - encore.confdistmatrix.set_rmsd_matrix_elements, - select="name CA", - pairwise_align=True, - weights="mass", - n_jobs=1, + conf_dist_matrix = ( + encore.confdistmatrix.conformational_distance_matrix( + ens1, + encore.confdistmatrix.set_rmsd_matrix_elements, + select="name CA", + pairwise_align=True, + weights="mass", + n_jobs=1, + ) ) reference = rms.RMSD(ens1, select="name CA") reference.run() - err_msg = "Calculated RMSD values differ from " "the reference implementation" + err_msg = ( + "Calculated RMSD values differ from " + "the reference implementation" + ) for i, rmsd in enumerate(reference.results.rmsd): assert_allclose( conf_dist_matrix[0, i], @@ -189,25 +196,29 @@ def test_rmsd_matrix_with_superimposition(self, ens1): ) def test_rmsd_matrix_with_superimposition_custom_weights(self, ens1): - conf_dist_matrix = encore.confdistmatrix.conformational_distance_matrix( - ens1, - encore.confdistmatrix.set_rmsd_matrix_elements, - select="name CA", - pairwise_align=True, - weights="mass", - n_jobs=1, + conf_dist_matrix = ( + encore.confdistmatrix.conformational_distance_matrix( + ens1, + encore.confdistmatrix.set_rmsd_matrix_elements, + select="name CA", + pairwise_align=True, + weights="mass", + n_jobs=1, + ) ) - conf_dist_matrix_custom = encore.confdistmatrix.conformational_distance_matrix( - ens1, - encore.confdistmatrix.set_rmsd_matrix_elements, - select="name CA", - pairwise_align=True, - weights=( - ens1.select_atoms("name CA").masses, - ens1.select_atoms("name CA").masses, - ), - n_jobs=1, + conf_dist_matrix_custom = ( + encore.confdistmatrix.conformational_distance_matrix( + ens1, + encore.confdistmatrix.set_rmsd_matrix_elements, + select="name CA", + pairwise_align=True, + weights=( + ens1.select_atoms("name CA").masses, + ens1.select_atoms("name CA").masses, + ), + n_jobs=1, + ) ) for i in range(conf_dist_matrix_custom.size): @@ -224,7 +235,9 @@ def test_rmsd_matrix_without_superimposition(self, ens1): reference_rmsd = [] coordinates = ens1.trajectory.timeseries(selection, order="fac") for coord in coordinates: - reference_rmsd.append(rms.rmsd(coordinates[0], coord, superposition=False)) + reference_rmsd.append( + rms.rmsd(coordinates[0], coord, superposition=False) + ) confdist_matrix = encore.confdistmatrix.conformational_distance_matrix( ens1, @@ -347,8 +360,12 @@ def test_covariance_matrix_with_reference(self, ens1): estimator=encore.covariance.shrinkage_covariance_estimator, reference=ens1, ) - err_msg = "Covariance matrix from covariance estimation not as expected" - assert_allclose(covariance, reference_cov, rtol=0, atol=1.5e-4, err_msg=err_msg) + err_msg = ( + "Covariance matrix from covariance estimation not as expected" + ) + assert_allclose( + covariance, reference_cov, rtol=0, atol=1.5e-4, err_msg=err_msg + ) def test_hes_to_self(self, ens1): results, details = encore.hes([ens1, ens1]) @@ -408,7 +425,9 @@ def test_hes_align(self, ens1, ens2): def test_ces_to_self(self, ens1): results, details = encore.ces( [ens1, ens1], - clustering_method=encore.AffinityPropagationNative(preference=-3.0), + clustering_method=encore.AffinityPropagationNative( + preference=-3.0 + ), ) result_value = results[0, 1] expected_value = 0.0 @@ -451,7 +470,9 @@ def test_dres_to_self(self, ens1): ) def test_dres(self, ens1, ens2): - results, details = encore.dres([ens1, ens2], select="name CA and resnum 1-10") + results, details = encore.dres( + [ens1, ens2], select="name CA and resnum 1-10" + ) result_value = results[0, 1] upper_bound = 0.6 assert result_value < upper_bound, ( @@ -466,7 +487,9 @@ def test_dres_without_superimposition(self, ens1, ens2): distance_matrix = encore.get_distance_matrix( encore.merge_universes([ens1, ens2]), superimpose=False ) - results, details = encore.dres([ens1, ens2], distance_matrix=distance_matrix) + results, details = encore.dres( + [ens1, ens2], distance_matrix=distance_matrix + ) result_value = results[0, 1] expected_value = 0.68 assert_allclose( @@ -498,7 +521,9 @@ def test_dres_convergence(self, ens1): expected_values = [0.3, 0.0] results = encore.dres_convergence(ens1, 10) try: - assert_allclose(results[:, 0], expected_values, rtol=0, atol=1.5e-1) + assert_allclose( + results[:, 0], expected_values, rtol=0, atol=1.5e-1 + ) except AssertionError: # Random test failure is very rare, but repeating the failed test # just once would only assert that the test passes with 50% @@ -541,8 +566,12 @@ def test_hes_error_estimation(self, ens1): "Unexpected standard deviation for bootstrapped samples in" " Harmonic Ensemble similarity" ) - assert_allclose(average, expected_average, rtol=0, atol=1.5e2, err_msg=err_msg) - assert_allclose(stdev, expected_stdev, rtol=0, atol=1.5e2, err_msg=error_msg) + assert_allclose( + average, expected_average, rtol=0, atol=1.5e2, err_msg=err_msg + ) + assert_allclose( + stdev, expected_stdev, rtol=0, atol=1.5e2, err_msg=error_msg + ) def test_ces_error_estimation(self, ens1): expected_average = 0.03 @@ -551,7 +580,9 @@ def test_ces_error_estimation(self, ens1): [ens1, ens1], estimate_error=True, bootstrapping_samples=10, - clustering_method=encore.AffinityPropagationNative(preference=-2.0), + clustering_method=encore.AffinityPropagationNative( + preference=-2.0 + ), select="name CA and resnum 1-10", ) average = averages[0, 1] @@ -594,12 +625,16 @@ def test_ces_error_estimation_ensemble_bootstrap(self, ens1): "Unexpected average value for bootstrapped samples in" " Clustering Ensemble similarity" ) - assert_allclose(average, expected_average, rtol=0, atol=1.5e-1, err_msg=err_msg) + assert_allclose( + average, expected_average, rtol=0, atol=1.5e-1, err_msg=err_msg + ) error_msg = ( "Unexpected standard deviation for bootstrapped samples in" " Clustering Ensemble similarity" ) - assert_allclose(stdev, expected_stdev, rtol=0, atol=1.5e-1, err_msg=error_msg) + assert_allclose( + stdev, expected_stdev, rtol=0, atol=1.5e-1, err_msg=error_msg + ) def test_dres_error_estimation(self, ens1): average_upper_bound = 0.3 @@ -771,7 +806,9 @@ def test_clustering_two_methods_one_w_no_distance_matrix(self, ens1): def test_sklearn_affinity_propagation(self, ens1): pytest.importorskip("sklearn") cc1 = encore.cluster([ens1]) - cc2 = encore.cluster([ens1], method=encore.AffinityPropagation(random_state=0)) + cc2 = encore.cluster( + [ens1], method=encore.AffinityPropagation(random_state=0) + ) assert len(cc1) == len(cc2), ( "Native and sklearn implementations of affinity " "propagation don't agree: mismatch in number of " @@ -815,7 +852,8 @@ def test_cluster_add_metadata(self, cluster): ) metadata = np.append(metadata, 9) error_message = ( - "Size of metadata is not equal to the " "number of cluster elements" + "Size of metadata is not equal to the " + "number of cluster elements" ) with pytest.raises(TypeError, match=error_message): cluster.add_metadata("test2", metadata) @@ -838,7 +876,9 @@ def test_metadata_size_error(self): "not equal to the number of cluster elements" ) with pytest.raises(TypeError, match=error_message): - encore.Cluster(np.array([1, 1, 1]), 1, None, {"label": [1, 1, 1, 1]}) + encore.Cluster( + np.array([1, 1, 1]), 1, None, {"label": [1, 1, 1, 1]} + ) def test_cluster_iteration(self, cluster): test = [] @@ -948,7 +988,9 @@ def distance_matrix(self): def test_one(self, distance_matrix): preference = -float(np.median(distance_matrix.as_array()) * 10.0) - clustering_method = encore.AffinityPropagationNative(preference=preference) + clustering_method = encore.AffinityPropagationNative( + preference=preference + ) ccs = encore.cluster( None, distance_matrix=distance_matrix, method=clustering_method ) @@ -1009,10 +1051,16 @@ def test_dimensionality_reduction_two_ensembles(self, ens1, ens2): ), ) - def test_dimensionality_reduction_three_ensembles_two_identical(self, ens1, ens2): + def test_dimensionality_reduction_three_ensembles_two_identical( + self, ens1, ens2 + ): coordinates, details = encore.reduce_dimensionality([ens1, ens2, ens1]) - coordinates_ens1 = coordinates[:, np.where(details["ensemble_membership"] == 1)] - coordinates_ens3 = coordinates[:, np.where(details["ensemble_membership"] == 3)] + coordinates_ens1 = coordinates[ + :, np.where(details["ensemble_membership"] == 1) + ] + coordinates_ens3 = coordinates[ + :, np.where(details["ensemble_membership"] == 3) + ] assert_allclose( coordinates_ens1, coordinates_ens3, @@ -1027,7 +1075,9 @@ def test_dimensionality_reduction_specified_dimension(self, ens1, ens2): dimension = 3 coordinates, details = encore.reduce_dimensionality( [ens1, ens2], - method=encore.StochasticProximityEmbeddingNative(dimension=dimension), + method=encore.StochasticProximityEmbeddingNative( + dimension=dimension + ), ) assert_equal( coordinates.shape[0], diff --git a/testsuite/MDAnalysisTests/analysis/test_gnm.py b/testsuite/MDAnalysisTests/analysis/test_gnm.py index cee3ab33dc..19d5a00093 100644 --- a/testsuite/MDAnalysisTests/analysis/test_gnm.py +++ b/testsuite/MDAnalysisTests/analysis/test_gnm.py @@ -179,7 +179,9 @@ def test_closeContactGNMAnalysis_weights_None(universe, client_GNMAnalysis): def test_closeContactGNMAnalysis_select_CA(universe, client_GNMAnalysis): # Issue #4924 fix the bug of CA selection - gnm = mda.analysis.gnm.closeContactGNMAnalysis(universe, "name CA", weights=None) + gnm = mda.analysis.gnm.closeContactGNMAnalysis( + universe, "name CA", weights=None + ) gnm.run(stop=2, **client_GNMAnalysis) result = gnm.results assert len(result.times) == 2 diff --git a/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py b/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py index 9e854424fe..3a291050d4 100644 --- a/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py +++ b/testsuite/MDAnalysisTests/analysis/test_helix_analysis.py @@ -160,7 +160,9 @@ def test_local_screw_angles_plane_circle(): """ angdeg = np.arange(0, 360, 12, dtype=np.int32) angrad = np.deg2rad(angdeg, dtype=np.float64) - xyz = np.array([[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64) + xyz = np.array( + [[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64 + ) xyz[15, 1] = 0 # because np.sin(np.deg2rad(180)) = 1e-16 ?! screw = hel.local_screw_angles([1, 0, 0], [0, 1, 0], xyz) correct = np.zeros_like(angdeg) @@ -176,7 +178,9 @@ def test_local_screw_angles_ortho_circle(): """ angdeg = np.arange(0, 360, 12, dtype=np.int32) angrad = np.deg2rad(angdeg, dtype=np.float64) - xyz = np.array([[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64) + xyz = np.array( + [[np.cos(a), np.sin(a), 0] for a in angrad], dtype=np.float64 + ) xyz[15, 1] = 0 # because np.sin(np.deg2rad(180)) = 1e-16 ?! screw = hel.local_screw_angles([1, 0, 0], [0, 0, 1], xyz) correct = np.zeros_like(angdeg) @@ -242,7 +246,9 @@ def zigzag(): x x x x x """ n_atoms = 100 - u = mda.Universe.empty(100, atom_resindex=np.arange(n_atoms), trajectory=True) + u = mda.Universe.empty( + 100, atom_resindex=np.arange(n_atoms), trajectory=True + ) xyz = np.array( list( zip( @@ -301,7 +307,9 @@ def test_helix_analysis_zigzag(zigzag, ref_axis, screw_angles): origins = zigzag.atoms.positions[1:-1].copy() origins[:, 0] = 0 assert_almost_equal(properties["local_origins"], origins, decimal=4) - assert_almost_equal(properties["local_screw_angles"], screw_angles * 49, decimal=4) + assert_almost_equal( + properties["local_screw_angles"], screw_angles * 49, decimal=4 + ) def square_oct(n_rep=10): @@ -340,7 +348,9 @@ def test_helix_analysis_square_oct(): properties = hel.helix_analysis(u.atoms.positions, ref_axis=[0, 0, 1]) twist_trans = [102.76438, 32.235607] twists = ([90] * 2 + twist_trans + [45] * 6 + twist_trans[::-1]) * n_rep - assert_almost_equal(properties["local_twists"], twists[: n_atoms - 3], decimal=4) + assert_almost_equal( + properties["local_twists"], twists[: n_atoms - 3], decimal=4 + ) res_trans = [3.503159, 11.167775] res = ([4] * 2 + res_trans + [8] * 6 + res_trans[::-1]) * n_rep assert_almost_equal( @@ -408,7 +418,9 @@ def test_helix_analysis_square_oct(): ] * n_rep # not quite 0, comes out as 1.32e-06 - assert_almost_equal(properties["local_screw_angles"], screw[:-2], decimal=3) + assert_almost_equal( + properties["local_screw_angles"], screw[:-2], decimal=3 + ) class TestHELANAL(object): @@ -421,13 +433,17 @@ def psf_ca(self): @pytest.fixture() def helanal(self, psf_ca): - ha = hel.HELANAL(psf_ca, select="resnum 161-187", flatten_single_helix=True) + ha = hel.HELANAL( + psf_ca, select="resnum 161-187", flatten_single_helix=True + ) return ha.run(start=10, stop=80) def test_regression_summary(self, helanal): bends = helanal.results.summary["all_bends"] old_helanal = read_bending_matrix(HELANAL_BENDING_MATRIX_SUBSET) - assert_almost_equal(np.triu(bends["mean"], 1), old_helanal["Mean"], decimal=1) + assert_almost_equal( + np.triu(bends["mean"], 1), old_helanal["Mean"], decimal=1 + ) assert_almost_equal( np.triu(bends["sample_sd"], 1), old_helanal["SD"], decimal=1 ) @@ -454,7 +470,9 @@ def test_regression_values(self): calculated = ha.results[key][0] msg = "Mismatch between calculated and reference {}" - assert_almost_equal(calculated, value, decimal=4, err_msg=msg.format(key)) + assert_almost_equal( + calculated, value, decimal=4, err_msg=msg.format(key) + ) def test_multiple_selections(self, psf_ca): ha = hel.HELANAL( diff --git a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py index b3b3bd34f2..97eeb6cc01 100644 --- a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py +++ b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel.py @@ -245,7 +245,9 @@ def actual_function_int(t): tau2 = 1 tau3 = 0.1 return ( - A1 * np.exp(-t / tau1) + A2 * np.exp(-t / tau2) + A3 * np.exp(-t / tau3) + A1 * np.exp(-t / tau1) + + A2 * np.exp(-t / tau2) + + A3 * np.exp(-t / tau3) ) hbond.solution["time"] = time = np.arange(0, 6.0, 0.01) @@ -319,7 +321,9 @@ def test_solve_before_run_VE(self, u, hydrogens, oxygens, nitrogens): hbond.solve() @mock.patch("MDAnalysis.coordinates.TRZ.TRZReader._read_frame") - def test_unslicable_traj_VE(self, mock_read, u, hydrogens, oxygens, nitrogens): + def test_unslicable_traj_VE( + self, mock_read, u, hydrogens, oxygens, nitrogens + ): mock_read.side_effect = TypeError with pytest.raises(ValueError): diff --git a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py index 70b67e08df..e1822b62fa 100644 --- a/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py +++ b/testsuite/MDAnalysisTests/analysis/test_hydrogenbondautocorrel_deprecated.py @@ -248,7 +248,9 @@ def actual_function_int(t): tau2 = 1 tau3 = 0.1 return ( - A1 * np.exp(-t / tau1) + A2 * np.exp(-t / tau2) + A3 * np.exp(-t / tau3) + A1 * np.exp(-t / tau1) + + A2 * np.exp(-t / tau2) + + A3 * np.exp(-t / tau3) ) hbond.solution["time"] = time = np.arange(0, 6.0, 0.01) @@ -322,7 +324,9 @@ def test_solve_before_run_VE(self, u, hydrogens, oxygens, nitrogens): hbond.solve() @mock.patch("MDAnalysis.coordinates.TRZ.TRZReader._read_frame") - def test_unslicable_traj_VE(self, mock_read, u, hydrogens, oxygens, nitrogens): + def test_unslicable_traj_VE( + self, mock_read, u, hydrogens, oxygens, nitrogens + ): mock_read.side_effect = TypeError with pytest.raises(ValueError): diff --git a/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py b/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py index b25b89f35a..2d70da9915 100644 --- a/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py +++ b/testsuite/MDAnalysisTests/analysis/test_hydrogenbonds_analysis.py @@ -89,10 +89,18 @@ def test_hbond_analysis(self, h): "angle": {"mean": 158.9038039, "std": 12.0362826}, } - assert_allclose(np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"]) - assert_allclose(np.std(h.results.hbonds[:, 4]), reference["distance"]["std"]) - assert_allclose(np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"]) - assert_allclose(np.std(h.results.hbonds[:, 5]), reference["angle"]["std"]) + assert_allclose( + np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"] + ) + assert_allclose( + np.std(h.results.hbonds[:, 4]), reference["distance"]["std"] + ) + assert_allclose( + np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"] + ) + assert_allclose( + np.std(h.results.hbonds[:, 5]), reference["angle"]["std"] + ) def test_count_by_time(self, h): @@ -203,7 +211,9 @@ def universe(): @staticmethod @pytest.fixture(scope="class") def hydrogen_bonds(universe, client_HydrogenBondAnalysis): - h = HydrogenBondAnalysis(universe, **TestHydrogenBondAnalysisIdeal.kwargs) + h = HydrogenBondAnalysis( + universe, **TestHydrogenBondAnalysisIdeal.kwargs + ) h.run(**client_HydrogenBondAnalysis) return h @@ -279,7 +289,9 @@ def test_hydrogen_bond_lifetime(self, hydrogen_bonds): assert_array_equal(timeseries, [1, 0, 0]) def test_hydrogen_bond_lifetime_intermittency(self, hydrogen_bonds): - tau_timeseries, timeseries = hydrogen_bonds.lifetime(tau_max=2, intermittency=1) + tau_timeseries, timeseries = hydrogen_bonds.lifetime( + tau_max=2, intermittency=1 + ) assert_array_equal(timeseries, 1) def test_no_attr_hbonds(self, universe): @@ -288,7 +300,9 @@ def test_no_attr_hbonds(self, universe): with pytest.raises(NoDataError, match=".hbonds attribute is None"): hbonds.lifetime(tau_max=2, intermittency=1) - def test_logging_step_not_1(self, universe, caplog, client_HydrogenBondAnalysis): + def test_logging_step_not_1( + self, universe, caplog, client_HydrogenBondAnalysis + ): hbonds = HydrogenBondAnalysis(universe, **self.kwargs) # using step 2 hbonds.run(**client_HydrogenBondAnalysis, step=2) @@ -296,7 +310,9 @@ def test_logging_step_not_1(self, universe, caplog, client_HydrogenBondAnalysis) caplog.set_level(logging.WARNING) hbonds.lifetime(tau_max=2, intermittency=1) - warning = "Autocorrelation: Hydrogen bonds were computed with " "step > 1." + warning = ( + "Autocorrelation: Hydrogen bonds were computed with " "step > 1." + ) assert any(warning in rec.getMessage() for rec in caplog.records) @@ -371,7 +387,9 @@ def universe(): @staticmethod @pytest.fixture(scope="class") def hydrogen_bonds(universe, client_HydrogenBondAnalysis): - h = HydrogenBondAnalysis(universe, **TestHydrogenBondAnalysisNoRes.kwargs) + h = HydrogenBondAnalysis( + universe, **TestHydrogenBondAnalysisNoRes.kwargs + ) h.run(**client_HydrogenBondAnalysis) return h @@ -479,7 +497,9 @@ def test_between_all(self, universe, client_HydrogenBondAnalysis): [6, 7, 8], # protein-protein ] expected_hbond_distances = [2.5, 3.0, 3.0] - assert_array_equal(hbonds.results.hbonds[:, 1:4], expected_hbond_indices) + assert_array_equal( + hbonds.results.hbonds[:, 1:4], expected_hbond_indices + ) assert_allclose(hbonds.results.hbonds[:, 4], expected_hbond_distances) def test_between_PW(self, universe, client_HydrogenBondAnalysis): @@ -492,7 +512,9 @@ def test_between_PW(self, universe, client_HydrogenBondAnalysis): # indices of [donor, hydrogen, acceptor] for each hydrogen bond expected_hbond_indices = [[3, 4, 6]] # protein-water expected_hbond_distances = [3.0] - assert_array_equal(hbonds.results.hbonds[:, 1:4], expected_hbond_indices) + assert_array_equal( + hbonds.results.hbonds[:, 1:4], expected_hbond_indices + ) assert_allclose(hbonds.results.hbonds[:, 4], expected_hbond_distances) def test_between_PW_PP(self, universe, client_HydrogenBondAnalysis): @@ -514,7 +536,9 @@ def test_between_PW_PP(self, universe, client_HydrogenBondAnalysis): [6, 7, 8], # protein-protein ] expected_hbond_distances = [3.0, 3.0] - assert_array_equal(hbonds.results.hbonds[:, 1:4], expected_hbond_indices) + assert_array_equal( + hbonds.results.hbonds[:, 1:4], expected_hbond_indices + ) assert_allclose(hbonds.results.hbonds[:, 4], expected_hbond_distances) @@ -605,7 +629,9 @@ def h(self, universe): def test_guess_hydrogens(self, h): - ref_hydrogens = "(resname TIP3 and name H1) or (resname TIP3 and name H2)" + ref_hydrogens = ( + "(resname TIP3 and name H1) or (resname TIP3 and name H2)" + ) hydrogens = h.guess_hydrogens(select="all") assert hydrogens == ref_hydrogens @@ -663,10 +689,18 @@ def test_hbond_analysis(self, h): "angle": {"mean": 157.07768079, "std": 9.72636682}, } - assert_allclose(np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"]) - assert_allclose(np.std(h.results.hbonds[:, 4]), reference["distance"]["std"]) - assert_allclose(np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"]) - assert_allclose(np.std(h.results.hbonds[:, 5]), reference["angle"]["std"]) + assert_allclose( + np.mean(h.results.hbonds[:, 4]), reference["distance"]["mean"] + ) + assert_allclose( + np.std(h.results.hbonds[:, 4]), reference["distance"]["std"] + ) + assert_allclose( + np.mean(h.results.hbonds[:, 5]), reference["angle"]["mean"] + ) + assert_allclose( + np.std(h.results.hbonds[:, 5]), reference["angle"]["std"] + ) def test_count_by_time(self, h): diff --git a/testsuite/MDAnalysisTests/analysis/test_leaflet.py b/testsuite/MDAnalysisTests/analysis/test_leaflet.py index 0760be0f95..e968bbf8c9 100644 --- a/testsuite/MDAnalysisTests/analysis/test_leaflet.py +++ b/testsuite/MDAnalysisTests/analysis/test_leaflet.py @@ -61,7 +61,10 @@ def test_leaflet_finder(self, universe, lipid_heads): lfls = LeafletFinder(universe, lipid_heads, pbc=True) top_heads, bottom_heads = lfls.groups() # Make top be... on top. - if top_heads.center_of_geometry()[2] < bottom_heads.center_of_geometry()[2]: + if ( + top_heads.center_of_geometry()[2] + < bottom_heads.center_of_geometry()[2] + ): top_heads, bottom_heads = (bottom_heads, top_heads) assert_equal( top_heads.indices, @@ -96,7 +99,9 @@ def test_pbc_on_off_difference(self, universe, lipid_heads): import networkx lfls_pbc_on = LeafletFinder(universe, lipid_heads, cutoff=7, pbc=True) - lfls_pbc_off = LeafletFinder(universe, lipid_heads, cutoff=7, pbc=False) + lfls_pbc_off = LeafletFinder( + universe, lipid_heads, cutoff=7, pbc=False + ) pbc_on_graph = lfls_pbc_on.graph pbc_off_graph = lfls_pbc_off.graph diff_graph = networkx.difference(pbc_on_graph, pbc_off_graph) @@ -184,8 +189,13 @@ def test_write_selection(self, universe, lipid_heads, tmpdir): ] ) - assert self.lines2one(open("leaflet.vmd").readlines()) == expected_output + assert ( + self.lines2one(open("leaflet.vmd").readlines()) + == expected_output + ) def test_component_index_is_not_none(self, universe, lipid_heads): lfls_ag = LeafletFinder(universe, lipid_heads, cutoff=15.0, pbc=True) - assert_almost_equal(len(lfls_ag.groups(component_index=0)), 180, decimal=4) + assert_almost_equal( + len(lfls_ag.groups(component_index=0)), 180, decimal=4 + ) diff --git a/testsuite/MDAnalysisTests/analysis/test_lineardensity.py b/testsuite/MDAnalysisTests/analysis/test_lineardensity.py index 67ea3f67aa..f775e6073a 100644 --- a/testsuite/MDAnalysisTests/analysis/test_lineardensity.py +++ b/testsuite/MDAnalysisTests/analysis/test_lineardensity.py @@ -90,12 +90,16 @@ def test_invalid_grouping(client_LinearDensity): ) # test data for grouping='residues' -expected_masses_residues = np.array([18.0154, 18.0154, 18.0154, 18.0154, 18.0154]) +expected_masses_residues = np.array( + [18.0154, 18.0154, 18.0154, 18.0154, 18.0154] +) expected_charges_residues = np.array([0, 0, 0, 0, 0]) expected_xmass_residues = np.array( [0.0, 0.0, 0.0, 0.00717967, 0.00478644, 0.0, 0.0, 0.0, 0.0, 0.0] ) -expected_xcharge_residues = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) +expected_xcharge_residues = np.array( + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +) # test data for grouping='segments' expected_masses_segments = np.array([90.0770]) @@ -103,10 +107,14 @@ def test_invalid_grouping(client_LinearDensity): expected_xmass_segments = np.array( [0.0, 0.0, 0.0, 0.01196611, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] ) -expected_xcharge_segments = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) +expected_xcharge_segments = np.array( + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +) # test data for grouping='fragments' -expected_masses_fragments = np.array([18.0154, 18.0154, 18.0154, 18.0154, 18.0154]) +expected_masses_fragments = np.array( + [18.0154, 18.0154, 18.0154, 18.0154, 18.0154] +) expected_charges_fragments = np.array([0, 0, 0, 0, 0]) expected_xmass_fragments = np.array( [0.0, 0.0, 0.0, 0.00717967, 0.00478644, 0.0, 0.0, 0.0, 0.0, 0.0] @@ -160,7 +168,9 @@ def test_lineardensity( universe = mda.Universe(waterPSF, waterDCD) sel_string = "all" selection = universe.select_atoms(sel_string) - ld = LinearDensity(selection, grouping, binsize=5).run(**client_LinearDensity) + ld = LinearDensity(selection, grouping, binsize=5).run( + **client_LinearDensity + ) assert_allclose(ld.masses, expected_masses) assert_allclose(ld.charges, expected_charges) # rtol changed here due to floating point imprecision @@ -231,9 +241,13 @@ def test_old_name_deprecations(): assert_allclose(ld.results.x.pos, ld.results.x.mass_density) assert_allclose(ld.results.x.pos_std, ld.results.x.mass_density_stddev) assert_allclose(ld.results.x.char, ld.results.x.charge_density) - assert_allclose(ld.results.x.char_std, ld.results.x.charge_density_stddev) + assert_allclose( + ld.results.x.char_std, ld.results.x.charge_density_stddev + ) for key in testdict.keys(): - assert_allclose(ld.results["x"][key], ld.results["x"][testdict[key]]) + assert_allclose( + ld.results["x"][key], ld.results["x"][testdict[key]] + ) # Check that no DeprecationWarning is raised with new attributes with no_deprecated_call(): @@ -257,10 +271,16 @@ def test_parallel_analysis(testing_Universe): ld1 = LinearDensity(selection1, binsize=1).run() ld2 = LinearDensity(selection2, binsize=1).run() ld_whole = LinearDensity(selection_whole, binsize=1).run() - with pytest.warns(DeprecationWarning, match="`_add_other_results` is deprecated!"): + with pytest.warns( + DeprecationWarning, match="`_add_other_results` is deprecated!" + ): ld1._add_other_results(ld2) - assert_allclose(ld1.results.z.mass_density, ld_whole.results.z.mass_density) - assert_allclose(ld1.results.x.mass_density, ld_whole.results.x.mass_density) + assert_allclose( + ld1.results.z.mass_density, ld_whole.results.z.mass_density + ) + assert_allclose( + ld1.results.x.mass_density, ld_whole.results.x.mass_density + ) def test_class_is_parallelizable(): @@ -271,8 +291,11 @@ def test_class_is_parallelizable(): def test_supported_backends(): - assert mda.analysis.lineardensity.LinearDensity.get_supported_backends() == ( - "serial", - "multiprocessing", - "dask", + assert ( + mda.analysis.lineardensity.LinearDensity.get_supported_backends() + == ( + "serial", + "multiprocessing", + "dask", + ) ) diff --git a/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py b/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py index 140dba89b1..61577599a0 100644 --- a/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py +++ b/testsuite/MDAnalysisTests/analysis/test_nuclinfo.py @@ -234,6 +234,8 @@ def test_hydroxyl(u, seg, i, expected_value): (8, 9, 10, "RNAA", "RNAA", "RNAA", 34.50106), ), ) -def test_pseudo_dihe_baseflip(u, bp1, bp2, i, seg1, seg2, seg3, expected_value): +def test_pseudo_dihe_baseflip( + u, bp1, bp2, i, seg1, seg2, seg3, expected_value +): val = nuclinfo.pseudo_dihe_baseflip(u, bp1, bp2, i, seg1, seg2, seg3) assert_almost_equal(val, expected_value, decimal=3) diff --git a/testsuite/MDAnalysisTests/analysis/test_pca.py b/testsuite/MDAnalysisTests/analysis/test_pca.py index b0400e5dea..663aa5e68f 100644 --- a/testsuite/MDAnalysisTests/analysis/test_pca.py +++ b/testsuite/MDAnalysisTests/analysis/test_pca.py @@ -99,13 +99,17 @@ def test_cum_var(pca): def test_pcs(pca): - assert_equal(pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3)) + assert_equal( + pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3) + ) def test_pcs_n_components(u): pca = PCA(u, select=SELECTION).run() assert_equal(pca.n_components, pca._n_atoms * 3) - assert_equal(pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3)) + assert_equal( + pca.results.p_components.shape, (pca._n_atoms * 3, pca._n_atoms * 3) + ) pca.n_components = 10 assert_equal(pca.n_components, 10) assert_equal(pca.results.p_components.shape, (pca._n_atoms * 3, 10)) @@ -187,7 +191,9 @@ def test_project_none_anchor(u, pca): group = u.select_atoms("resnum 1") with pytest.raises(ValueError) as exc: func = pca.project_single_frame(0, group=group, anchor=None) - assert ("'anchor' cannot be 'None'" + " if 'group' is not 'None'") in str(exc.value) + assert ("'anchor' cannot be 'None'" + " if 'group' is not 'None'") in str( + exc.value + ) def test_project_more_anchor(u, pca): @@ -201,7 +207,9 @@ def test_project_less_anchor(u, pca): group = u.select_atoms("all") with pytest.raises(ValueError) as exc: project = pca.project_single_frame(0, group=group, anchor="name CB") - assert ("Some residues in 'group'" + " do not have an 'anchor'") in str(exc.value) + assert ("Some residues in 'group'" + " do not have an 'anchor'") in str( + exc.value + ) def test_project_invalid_anchor(u): @@ -267,7 +275,9 @@ def test_project_extrapolate_translation(u_fresh): project = pca.project_single_frame(0, group=group, anchor="name CA") distances_original = mda.lib.distances.self_distance_array(group.positions) - distances_new = mda.lib.distances.self_distance_array(project(group).positions) + distances_new = mda.lib.distances.self_distance_array( + project(group).positions + ) assert_allclose(distances_original, distances_new, rtol=1e-05) @@ -376,7 +386,9 @@ def test_compare_wrong_class(u, pca, method): assert "must be another PCA class" in str(exc.value) -@pytest.mark.parametrize("attr", ("p_components", "variance", "cumulated_variance")) +@pytest.mark.parametrize( + "attr", ("p_components", "variance", "cumulated_variance") +) def test_pca_attr_warning(u, attr): pca = PCA(u, select=SELECTION).run(stop=2) wmsg = f"The `{attr}` attribute was deprecated in MDAnalysis 2.0.0" diff --git a/testsuite/MDAnalysisTests/analysis/test_persistencelength.py b/testsuite/MDAnalysisTests/analysis/test_persistencelength.py index 68dc7bcb58..3cbee2952c 100644 --- a/testsuite/MDAnalysisTests/analysis/test_persistencelength.py +++ b/testsuite/MDAnalysisTests/analysis/test_persistencelength.py @@ -68,7 +68,9 @@ def test_lb(self, p_run): def test_fit(self, p_run): assert_almost_equal(p_run.results.lp, 6.504, 3) - assert len(p_run.results.fit) == len(p_run.results.bond_autocorrelation) + assert len(p_run.results.fit) == len( + p_run.results.bond_autocorrelation + ) def test_raise_NoDataError(self, p): # Ensure that a NoDataError is raised if perform_fit() diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index 505e446192..aa14071069 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -97,7 +97,9 @@ def test_exclusion(sels): assert rdf.results.count.sum() == 4 -@pytest.mark.parametrize("attr, count", [("residue", 8), ("segment", 0), ("chain", 8)]) +@pytest.mark.parametrize( + "attr, count", [("residue", 8), ("segment", 0), ("chain", 8)] +) def test_ignore_same_residues(sels, attr, count): # should see two distances with 4 counts each s1, s2 = sels diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index ad88a839cd..3faac69ce3 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -120,7 +120,9 @@ def test_density(u, sels, density, value): assert_almost_equal(max(rdf.results.rdf[0][0][0]), value) if not density: s1 = u.select_atoms("name ZND and resid 289") - s2 = u.select_atoms("name OD1 and resid 51 and sphzone 5.0 (resid 289)") + s2 = u.select_atoms( + "name OD1 and resid 51 and sphzone 5.0 (resid 289)" + ) rdf_ref = InterRDF(s1, s2).run() assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) @@ -143,7 +145,9 @@ def test_norm(u, sels, norm, value): assert_allclose(max(rdf.results.rdf[0][0][0]), value) if norm == "rdf": s1 = u.select_atoms("name ZND and resid 289") - s2 = u.select_atoms("name OD1 and resid 51 and sphzone 5.0 (resid 289)") + s2 = u.select_atoms( + "name OD1 and resid 51 and sphzone 5.0 (resid 289)" + ) rdf_ref = InterRDF(s1, s2).run() assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) diff --git a/testsuite/MDAnalysisTests/analysis/test_results.py b/testsuite/MDAnalysisTests/analysis/test_results.py index 61773c1a47..adfbc4b506 100644 --- a/testsuite/MDAnalysisTests/analysis/test_results.py +++ b/testsuite/MDAnalysisTests/analysis/test_results.py @@ -156,7 +156,9 @@ def merger(self): @pytest.mark.parametrize("n", [1, 2, 5, 14]) def test_all_results(self, results_0, results_1, merger, n): - objects = [obj for obj, _ in zip(cycle([results_0, results_1]), range(n))] + objects = [ + obj for obj, _ in zip(cycle([results_0, results_1]), range(n)) + ] arr = [i for _, i in zip(range(n), cycle([0, 1]))] answers = { @@ -179,7 +181,9 @@ def test_missing_aggregator(self, results_0, results_1, merger): original_float_lookup = merger._lookup.get("float") merger._lookup["float"] = None - with pytest.raises(ValueError, match="No aggregation function for key='float'"): + with pytest.raises( + ValueError, match="No aggregation function for key='float'" + ): merger.merge([results_0, results_1], require_all_aggregators=True) merger._lookup["float"] = original_float_lookup diff --git a/testsuite/MDAnalysisTests/analysis/test_rms.py b/testsuite/MDAnalysisTests/analysis/test_rms.py index e1feb883e5..f39baa68f1 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rms.py +++ b/testsuite/MDAnalysisTests/analysis/test_rms.py @@ -72,7 +72,8 @@ def p_last(self, u2): def test_p_frames(self, p_first, p_last): # check that these fixtures are really different assert ( - p_first.universe.trajectory.ts.frame != p_last.universe.trajectory.ts.frame + p_first.universe.trajectory.ts.frame + != p_last.universe.trajectory.ts.frame ) assert not np.allclose(p_first.positions, p_last.positions) @@ -116,7 +117,9 @@ def test_weights_and_superposition_1(self, u): weights=weights, superposition=True, ) - firstCoords = rms.rmsd(u.trajectory[0], u.trajectory[1], superposition=True) + firstCoords = rms.rmsd( + u.trajectory[0], u.trajectory[1], superposition=True + ) assert_almost_equal(weighted, firstCoords, decimal=5) def test_weights_and_superposition_2(self, u): @@ -216,7 +219,9 @@ def test_rmsd_frames(self, universe, correct_values, client_RMSD): err_msg="error: rmsd profile should match" + "test values", ) - def test_rmsd_unicode_selection(self, universe, correct_values, client_RMSD): + def test_rmsd_unicode_selection( + self, universe, correct_values, client_RMSD + ): RMSD = MDAnalysis.analysis.rms.RMSD(universe, select="name CA") RMSD.run(step=49, **client_RMSD) assert_almost_equal( @@ -228,9 +233,9 @@ def test_rmsd_unicode_selection(self, universe, correct_values, client_RMSD): def test_rmsd_atomgroup_selections(self, universe, client_RMSD): # see Issue #1684 - R1 = MDAnalysis.analysis.rms.RMSD(universe.atoms, select="resid 1-30").run( - **client_RMSD - ) + R1 = MDAnalysis.analysis.rms.RMSD( + universe.atoms, select="resid 1-30" + ).run(**client_RMSD) R2 = MDAnalysis.analysis.rms.RMSD( universe.atoms.select_atoms("name CA"), select="resid 1-30" ).run(**client_RMSD) @@ -290,11 +295,13 @@ def test_weights_mass_is_mass_weighted(self, universe, client_RMSD): "and universe.atoms.masses", ) - def test_custom_weighted_list(self, universe, correct_values_mass, client_RMSD): + def test_custom_weighted_list( + self, universe, correct_values_mass, client_RMSD + ): weights = universe.atoms.masses - RMSD = MDAnalysis.analysis.rms.RMSD(universe, weights=list(weights)).run( - step=49, **client_RMSD - ) + RMSD = MDAnalysis.analysis.rms.RMSD( + universe, weights=list(weights) + ).run(step=49, **client_RMSD) assert_almost_equal( RMSD.results.rmsd, correct_values_mass, @@ -354,7 +361,9 @@ def test_rmsd_mismatched_weights_raises_ValueError(self, universe): universe, weights=universe.atoms.masses[:-1] ) - def test_rmsd_misuse_weights_for_groupselection_raises_TypeError(self, universe): + def test_rmsd_misuse_weights_for_groupselection_raises_TypeError( + self, universe + ): with pytest.raises(TypeError): RMSD = MDAnalysis.analysis.rms.RMSD( universe, @@ -382,7 +391,9 @@ def test_rmsd_list_of_weights_wrong_length(self, universe): weights_groupselections=[None], ) - def test_rmsd_group_selections(self, universe, correct_values_group, client_RMSD): + def test_rmsd_group_selections( + self, universe, correct_values_group, client_RMSD + ): RMSD = MDAnalysis.analysis.rms.RMSD( universe, groupselections=["backbone", "name CA"] ).run(step=49, **client_RMSD) @@ -508,7 +519,9 @@ def test_rmsf_identical_frames(self, universe, tmpdir, client_RMSF): ) def test_rmsf_attr_warning(self, universe, client_RMSF): - rmsfs = rms.RMSF(universe.select_atoms("name CA")).run(stop=2, **client_RMSF) + rmsfs = rms.RMSF(universe.select_atoms("name CA")).run( + stop=2, **client_RMSF + ) wmsg = "The `rmsf` attribute was deprecated in MDAnalysis 2.0.0" with pytest.warns(DeprecationWarning, match=wmsg): diff --git a/testsuite/MDAnalysisTests/analysis/test_wbridge.py b/testsuite/MDAnalysisTests/analysis/test_wbridge.py index e364430694..2b53d2f1d3 100644 --- a/testsuite/MDAnalysisTests/analysis/test_wbridge.py +++ b/testsuite/MDAnalysisTests/analysis/test_wbridge.py @@ -287,7 +287,9 @@ def wb_multiframe(): wb.results.network.append( { (0, None, 3, 2, 2.0, 180.0): { - (4, 2, 5, None, 2.0, 180.0): {(5, None, 11, 12, 2.0, 180.0): None} + (4, 2, 5, None, 2.0, 180.0): { + (5, None, 11, 12, 2.0, 180.0): None + } } } ) @@ -689,10 +691,18 @@ def test_timeseries_wba(self, universe_branch): wb.run(verbose=False) timeseries = sorted(wb.results.timeseries[0]) - assert_equal(timeseries[0][:4], (0, 2, ("ALA", 1, "O"), ("SOL", 2, "HW1"))) - assert_equal(timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW"))) - assert_equal(timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O"))) - assert_equal(timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O"))) + assert_equal( + timeseries[0][:4], (0, 2, ("ALA", 1, "O"), ("SOL", 2, "HW1")) + ) + assert_equal( + timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW")) + ) + assert_equal( + timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O")) + ) + assert_equal( + timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O")) + ) def test_timeseries_hba(self, universe_branch): """Test if the time series data is correctly generated in hydrogen bond analysis format""" @@ -706,10 +716,18 @@ def test_timeseries_hba(self, universe_branch): wb.run(verbose=False) timeseries = sorted(wb.results.timeseries[0]) - assert_equal(timeseries[0][:4], (2, 0, ("SOL", 2, "HW1"), ("ALA", 1, "O"))) - assert_equal(timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW"))) - assert_equal(timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O"))) - assert_equal(timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O"))) + assert_equal( + timeseries[0][:4], (2, 0, ("SOL", 2, "HW1"), ("ALA", 1, "O")) + ) + assert_equal( + timeseries[1][:4], (3, 4, ("SOL", 2, "HW2"), ("SOL", 3, "OW")) + ) + assert_equal( + timeseries[2][:4], (5, 7, ("SOL", 3, "HW1"), ("ALA", 4, "O")) + ) + assert_equal( + timeseries[3][:4], (6, 8, ("SOL", 3, "HW2"), ("ALA", 5, "O")) + ) @pytest.mark.parametrize("distance_type", ["hydrogen", "heavy"]) def test_acceptor_12water_accepter(self, universe_AWA_AWWA, distance_type): @@ -750,7 +768,9 @@ def test_count_by_type_single_link(self, universe_DWA): universe_DWA, "protein and (resid 1)", "protein and (resid 4)" ) wb.run(verbose=False) - assert_equal(wb.count_by_type(), [(1, 4, "ALA", 1, "H", "ALA", 4, "O", 1.0)]) + assert_equal( + wb.count_by_type(), [(1, 4, "ALA", 1, "H", "ALA", 4, "O", 1.0)] + ) def test_count_by_type_multiple_link(self, universe_AWA_AWWA): """ @@ -792,10 +812,12 @@ def test_count_by_type_filter(self, wb_multiframe): """ def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ - -1 - ] + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( + current[0] + ) + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( + current[-1] + ) sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -834,10 +856,12 @@ def test_count_by_type_merge(self, wb_multiframe): """ def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ - -1 - ] + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( + current[0] + ) + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( + current[-1] + ) sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -867,10 +891,12 @@ def test_count_by_type_order(self, wb_multiframe): """ def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ - -1 - ] + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( + current[0] + ) + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( + current[-1] + ) sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -906,7 +932,9 @@ def test_count_by_time(self, wb_multiframe): This test tests if count_by_times() works. :return: """ - assert_equal(wb_multiframe.count_by_time(), [(0, 1), (1, 1), (2, 1), (3, 1)]) + assert_equal( + wb_multiframe.count_by_time(), [(0, 1), (1, 1), (2, 1), (3, 1)] + ) def test_count_by_time_weight(self, universe_AWA_AWWA): """ @@ -923,10 +951,12 @@ def test_count_by_time_weight(self, universe_AWA_AWWA): wb.run(verbose=False) def analysis(current, output, u): - sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = current[0] - atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = current[ - -1 - ] + sele1_index, sele1_heavy_index, atom2, heavy_atom2, dist, angle = ( + current[0] + ) + atom1, heavy_atom1, sele2_index, sele2_heavy_index, dist, angle = ( + current[-1] + ) sele1 = u.atoms[sele1_index] sele2 = u.atoms[sele2_index] (s1_resname, s1_resid, s1_name) = ( @@ -992,7 +1022,9 @@ def test_timesteps_by_type(self, wb_multiframe): """Test the timesteps_by_type function""" timesteps = sorted(wb_multiframe.timesteps_by_type()) - assert_array_equal(timesteps[3], [1, 12, "ALA", 1, "H", "ALA", 6, "O", 0, 2]) + assert_array_equal( + timesteps[3], [1, 12, "ALA", 1, "H", "ALA", 6, "O", 0, 2] + ) def test_duplicate_water(self): """A case #3119 where diff --git a/testsuite/MDAnalysisTests/auxiliary/base.py b/testsuite/MDAnalysisTests/auxiliary/base.py index 03daaebe02..e3e82a0161 100644 --- a/testsuite/MDAnalysisTests/auxiliary/base.py +++ b/testsuite/MDAnalysisTests/auxiliary/base.py @@ -116,7 +116,9 @@ def reference_timestep(dt=1, offset=0): # for 'average': use low frequenct timestep, only step 2 within 0ps cutoff self.lowf_cutoff_average_rep = self.format_data([2, 2 * 2, 2**2]) # for 'closest': use offset timestep; no timestep within 0ps cutoff - self.offset_cutoff_closest_rep = self.format_data([np.nan, np.nan, np.nan]) + self.offset_cutoff_closest_rep = self.format_data( + [np.nan, np.nan, np.nan] + ) ## testing selection of time/data. Overload for each auxilairy format ## as appropraite. @@ -148,7 +150,9 @@ def test_dt(self, ref, reader): assert reader.dt == ref.dt, "dt does not match" def test_initial_time(self, ref, reader): - assert reader.initial_time == ref.initial_time, "initial time does not match" + assert ( + reader.initial_time == ref.initial_time + ), "initial time does not match" def test_first_step(self, ref, reader): # on first loading we should start at step 0 @@ -323,7 +327,8 @@ def test_represent_as_average_with_cutoff(self, ref, reader): assert_almost_equal( ts.aux.test, ref.lowf_cutoff_average_rep, - err_msg="Representative value does not match when " "applying cutoff", + err_msg="Representative value does not match when " + "applying cutoff", ) def test_read_offset_timestep(self, ref, reader): @@ -347,7 +352,8 @@ def test_represent_as_closest_with_cutoff(self, ref, reader): assert_almost_equal( ts.aux.test, ref.offset_cutoff_closest_rep, - err_msg="Representative value does not match when " "applying cutoff", + err_msg="Representative value does not match when " + "applying cutoff", ) def test_read_higher_freq_timestep(self, ref, reader): @@ -399,7 +405,8 @@ def test_auxiliary_read_ts_rewind(self, ref_universe): assert_equal( aux_info_0, aux_info_0_rewind, - "aux info was retrieved incorrectly " "after reading the last step", + "aux info was retrieved incorrectly " + "after reading the last step", ) def test_get_description(self, ref, reader): @@ -412,7 +419,9 @@ def test_get_description(self, ref, reader): def test_load_from_description(self, reader): description = reader.get_description() new = mda.auxiliary.core.auxreader(**description) - assert new == reader, "AuxReader reloaded from description does not match" + assert ( + new == reader + ), "AuxReader reloaded from description does not match" def test_step_to_frame_out_of_bounds(self, reader, ref): @@ -437,7 +446,9 @@ def test_step_to_frame_time_diff(self, reader, ref): # Test all 5 frames for idx in range(5): - frame, time_diff = reader.step_to_frame(idx, ts, return_time_diff=True) + frame, time_diff = reader.step_to_frame( + idx, ts, return_time_diff=True + ) assert frame == idx np.testing.assert_almost_equal(time_diff, idx * 0.1) diff --git a/testsuite/MDAnalysisTests/auxiliary/test_core.py b/testsuite/MDAnalysisTests/auxiliary/test_core.py index b17637daaf..8a630c6e48 100644 --- a/testsuite/MDAnalysisTests/auxiliary/test_core.py +++ b/testsuite/MDAnalysisTests/auxiliary/test_core.py @@ -28,12 +28,16 @@ def test_get_auxreader_for_none(): - with pytest.raises(ValueError, match="Must provide either auxdata or format"): + with pytest.raises( + ValueError, match="Must provide either auxdata or format" + ): mda.auxiliary.core.get_auxreader_for() def test_get_auxreader_for_wrong_auxdata(): - with pytest.raises(ValueError, match="Unknown auxiliary data format for auxdata:"): + with pytest.raises( + ValueError, match="Unknown auxiliary data format for auxdata:" + ): mda.auxiliary.core.get_auxreader_for(auxdata="test.none") @@ -43,7 +47,9 @@ def test_get_auxreader_for_wrong_format(): def test_notimplemented_read_next_timestep(): - with pytest.raises(NotImplementedError, match="BUG: Override " "_read_next_step()"): + with pytest.raises( + NotImplementedError, match="BUG: Override " "_read_next_step()" + ): reader = mda.auxiliary.base.AuxReader() @@ -53,6 +59,8 @@ def _read_next_step(self): def test_notimplemented_memory_usage(): - with pytest.raises(NotImplementedError, match="BUG: Override " "_memory_usage()"): + with pytest.raises( + NotImplementedError, match="BUG: Override " "_memory_usage()" + ): reader = No_Memory_Usage() reader._memory_usage() diff --git a/testsuite/MDAnalysisTests/auxiliary/test_edr.py b/testsuite/MDAnalysisTests/auxiliary/test_edr.py index 9da63cf2a7..8668c8a056 100644 --- a/testsuite/MDAnalysisTests/auxiliary/test_edr.py +++ b/testsuite/MDAnalysisTests/auxiliary/test_edr.py @@ -105,7 +105,9 @@ def __init__(self): def reference_auxstep(i): # create a reference AuxStep for step i t_init = self.initial_time - auxstep = mda.auxiliary.EDR.EDRStep(dt=self.dt, initial_time=t_init) + auxstep = mda.auxiliary.EDR.EDRStep( + dt=self.dt, initial_time=t_init + ) auxstep.step = i auxstep._data = get_auxstep_data(i) return auxstep @@ -226,7 +228,9 @@ def reader(ref): data = reader.data_dict[term] reader_unit = reader.unit_dict[term] try: - reader.data_dict[term] = units.convert(data, reader_unit, ref_unit) + reader.data_dict[term] = units.convert( + data, reader_unit, ref_unit + ) except ValueError: continue # some units not supported yet reader.rewind() @@ -237,7 +241,9 @@ def test_time_non_constant_dt(self, reader): reader.time_selector = None with pytest.raises( ValueError, - match="If dt is not constant, " "must have a valid time " "selector", + match="If dt is not constant, " + "must have a valid time " + "selector", ): reader.time @@ -263,7 +269,9 @@ def test_step_to_frame_time_diff(self, reader, ref): # Test all 4 frames for idx in range(4): - frame, time_diff = reader.step_to_frame(idx, ts, return_time_diff=True) + frame, time_diff = reader.step_to_frame( + idx, ts, return_time_diff=True + ) assert frame == idx assert_allclose(time_diff, idx * 0.002) @@ -326,7 +334,8 @@ def test_represent_as_average_with_cutoff(self, ref, reader): assert_allclose( ts.aux.test["Bond"], ref.lowf_cutoff_average_rep, - err_msg="Representative value does not match when " "applying cutoff", + err_msg="Representative value does not match when " + "applying cutoff", ) # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 @@ -354,7 +363,9 @@ def test_add_term_list_custom_names_from_file(self, ref, ref_universe): assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def test_add_term_list_custom_names_from_reader(self, ref_universe, reader): + def test_add_term_list_custom_names_from_reader( + self, ref_universe, reader + ): ref_universe.trajectory.add_auxiliary( {"bond": "Bond", "temp": "Temperature"}, reader ) @@ -363,18 +374,24 @@ def test_add_term_list_custom_names_from_reader(self, ref_universe, reader): assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def test_raise_error_if_auxname_already_assigned(self, ref_universe, reader): + def test_raise_error_if_auxname_already_assigned( + self, ref_universe, reader + ): with pytest.raises(ValueError, match="Auxiliary data with name"): ref_universe.trajectory.add_auxiliary("test", reader, "Bond") # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_add_single_term_custom_name_from_file(self, ref, ref_universe): - ref_universe.trajectory.add_auxiliary({"temp": "Temperature"}, ref.testdata) + ref_universe.trajectory.add_auxiliary( + {"temp": "Temperature"}, ref.testdata + ) ref_dict = get_auxstep_data(0) assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 - def test_add_single_term_custom_name_from_reader(self, ref_universe, reader): + def test_add_single_term_custom_name_from_reader( + self, ref_universe, reader + ): ref_universe.trajectory.add_auxiliary({"temp": "Temperature"}, reader) ref_dict = get_auxstep_data(0) assert ref_universe.trajectory.ts.aux.temp == ref_dict["Temperature"] @@ -395,7 +412,9 @@ def test_terms_update_on_iter(self, ref_universe, reader): # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_invalid_data_selector(self, ref, ref_universe): with pytest.raises(KeyError, match="'Nonsense' is not a key"): - ref_universe.trajectory.add_auxiliary({"something": "Nonsense"}, AUX_EDR) + ref_universe.trajectory.add_auxiliary( + {"something": "Nonsense"}, AUX_EDR + ) def test_read_all_times(self, reader): all_times_expected = np.array([0.0, 0.02, 0.04, 0.06]) @@ -433,7 +452,9 @@ def test_get_data_invalid_selections(self, reader, get_data_input): # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_warning_when_space_in_aux_spec(self, ref_universe, reader): with pytest.warns(UserWarning, match="Auxiliary name"): - ref_universe.trajectory.add_auxiliary({"Pres. DC": "Pres. DC"}, reader) + ref_universe.trajectory.add_auxiliary( + {"Pres. DC": "Pres. DC"}, reader + ) # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_warn_too_much_memory_usage(self, ref_universe, reader): @@ -462,7 +483,9 @@ def test_units_are_converted_by_EDRReader(self, reader): # TODO: Change order of aux_spec and auxdata for 3.0 release, cf. Issue #3811 def test_warning_when_unknown_unit(self, ref_universe, reader): with pytest.warns(UserWarning, match="Could not find"): - ref_universe.trajectory.add_auxiliary({"temp": "Temperature"}, reader) + ref_universe.trajectory.add_auxiliary( + {"temp": "Temperature"}, reader + ) def test_unit_conversion_is_optional(self, ref): reader = ref.reader( @@ -485,7 +508,9 @@ def test_unit_conversion_is_optional(self, ref): def test_single_frame_input_file(): """Previously, EDRReader could not handle EDR input files with only one frame. See Issue #3999.""" - reader = mda.auxiliary.EDR.EDRReader(AUX_EDR_SINGLE_FRAME, convert_units=False) + reader = mda.auxiliary.EDR.EDRReader( + AUX_EDR_SINGLE_FRAME, convert_units=False + ) ref_dict = get_auxstep_data(0) reader_data_dict = reader.auxstep.data assert ref_dict == reader_data_dict diff --git a/testsuite/MDAnalysisTests/auxiliary/test_xvg.py b/testsuite/MDAnalysisTests/auxiliary/test_xvg.py index 2fdaf52405..8926cabe32 100644 --- a/testsuite/MDAnalysisTests/auxiliary/test_xvg.py +++ b/testsuite/MDAnalysisTests/auxiliary/test_xvg.py @@ -75,7 +75,9 @@ def test_select_time_none(self, step): assert st is None def test_select_time_invalid_index(self, step): - with pytest.raises(ValueError, match="Time selector must be single index"): + with pytest.raises( + ValueError, match="Time selector must be single index" + ): step._select_time([0]) def test_select_data_none(self, step): @@ -168,7 +170,9 @@ def reader(ref): def test_get_auxreader_for(self, ref, reader): # Default reader of .xvg files is intead XVGReader, not XVGFileReader # so test specifying format - reader = mda.auxiliary.core.get_auxreader_for(ref.testdata, format=ref.format) + reader = mda.auxiliary.core.get_auxreader_for( + ref.testdata, format=ref.format + ) assert reader == ref.reader def test_reopen(self, reader): diff --git a/testsuite/MDAnalysisTests/converters/test_base.py b/testsuite/MDAnalysisTests/converters/test_base.py index 6d6f9f4d33..a8bebca0c3 100644 --- a/testsuite/MDAnalysisTests/converters/test_base.py +++ b/testsuite/MDAnalysisTests/converters/test_base.py @@ -41,7 +41,9 @@ class DerivedConverter(ConverterBase): pass assert issubclass(DerivedConverter, ConverterBase) - assert not issubclass(DerivedConverter, MDAnalysis.converters.base.ConverterBase) + assert not issubclass( + DerivedConverter, MDAnalysis.converters.base.ConverterBase + ) def test_converters_converterbase_no_warning(): diff --git a/testsuite/MDAnalysisTests/converters/test_openmm_parser.py b/testsuite/MDAnalysisTests/converters/test_openmm_parser.py index c0762955b2..7188499fd8 100644 --- a/testsuite/MDAnalysisTests/converters/test_openmm_parser.py +++ b/testsuite/MDAnalysisTests/converters/test_openmm_parser.py @@ -131,13 +131,17 @@ def test_masses(self, top): assert len(top.masses.values) == self.expected_n_atoms if self.expected_n_atoms: assert isinstance(top.masses.values, np.ndarray) - assert all(isinstance(mass, np.float64) for mass in top.masses.values) + assert all( + isinstance(mass, np.float64) for mass in top.masses.values + ) else: assert top.masses.values == [] def test_guessed_attributes(self, filename): u = mda.Universe(filename, topology_format="OPENMMTOPOLOGY") - u_guessed_attrs = [attr.attrname for attr in u._topology.guessed_attributes] + u_guessed_attrs = [ + attr.attrname for attr in u._topology.guessed_attributes + ] for attr in self.guessed_attrs: assert hasattr(u.atoms, attr) assert attr in u_guessed_attrs diff --git a/testsuite/MDAnalysisTests/converters/test_parmed.py b/testsuite/MDAnalysisTests/converters/test_parmed.py index 1214fbea4a..261d389603 100644 --- a/testsuite/MDAnalysisTests/converters/test_parmed.py +++ b/testsuite/MDAnalysisTests/converters/test_parmed.py @@ -57,7 +57,9 @@ def test_dimensions(self): self.ref.trajectory.ts.dimensions, rtol=0, atol=1e-3, - err_msg=("ParmEdReader failed to get unitcell dimensions " "from ParmEd"), + err_msg=( + "ParmEdReader failed to get unitcell dimensions " "from ParmEd" + ), ) def test_coordinates(self): @@ -77,7 +79,9 @@ def test_dimensions(self): self.ref.trajectory.ts.dimensions, rtol=0, atol=1e-3, - err_msg=("ParmEdReader failed to get unitcell dimensions " "from ParmEd"), + err_msg=( + "ParmEdReader failed to get unitcell dimensions " "from ParmEd" + ), ) def test_coordinates(self): @@ -199,9 +203,9 @@ def test_equivalent_atoms(self, ref, output): for attr in self.equal_atom_attrs: ra = getattr(r, attr) oa = getattr(o, attr) - assert ra == oa, "atom {} not equal for atoms {} and {}".format( - attr, r, o - ) + assert ( + ra == oa + ), "atom {} not equal for atoms {} and {}".format(attr, r, o) for attr in self.almost_equal_atom_attrs: ra = getattr(r, attr) @@ -211,7 +215,10 @@ def test_equivalent_atoms(self, ref, output): oa, rtol=0, atol=1e-2, - err_msg=(f"atom {attr} not almost equal for atoms " f"{r} and {o}"), + err_msg=( + f"atom {attr} not almost equal for atoms " + f"{r} and {o}" + ), ) @pytest.mark.parametrize("attr", ("bonds", "angles", "impropers", "cmaps")) diff --git a/testsuite/MDAnalysisTests/converters/test_parmed_parser.py b/testsuite/MDAnalysisTests/converters/test_parmed_parser.py index e4a6e1c892..1a11876fd4 100644 --- a/testsuite/MDAnalysisTests/converters/test_parmed_parser.py +++ b/testsuite/MDAnalysisTests/converters/test_parmed_parser.py @@ -90,7 +90,9 @@ def test_bonds_total_counts(self, top, filename): assert len(top.bonds.values) == len(unique) def test_angles_total_counts(self, top, filename): - unique = set([(a.atom1.idx, a.atom2.idx, a.atom3.idx) for a in filename.angles]) + unique = set( + [(a.atom1.idx, a.atom2.idx, a.atom3.idx) for a in filename.angles] + ) assert len(top.angles.values) == len(unique) def test_dihedrals_total_counts(self, top, filename): @@ -127,7 +129,9 @@ def test_cmaps_total_counts(self, top, filename): assert len(top.cmaps.values) == len(unique) def test_ureybradleys_total_counts(self, top, filename): - unique = set([(a.atom1.idx, a.atom2.idx) for a in filename.urey_bradleys]) + unique = set( + [(a.atom1.idx, a.atom2.idx) for a in filename.urey_bradleys] + ) assert len(top.ureybradleys.values) == len(unique) def test_elements(self, top): @@ -213,7 +217,9 @@ def test_dihedrals_identity(self, top, value): vals = top.dihedrals.values assert value in vals or value[::-1] in vals - @pytest.mark.parametrize("value", ((17, 19, 21, 41, 43), (60, 62, 64, 79, 81))) + @pytest.mark.parametrize( + "value", ((17, 19, 21, 41, 43), (60, 62, 64, 79, 81)) + ) def test_cmaps_identity(self, top, value): vals = top.cmaps.values assert value in vals or value[::-1] in vals diff --git a/testsuite/MDAnalysisTests/converters/test_rdkit.py b/testsuite/MDAnalysisTests/converters/test_rdkit.py index 5dc77889a0..31bc390b4f 100644 --- a/testsuite/MDAnalysisTests/converters/test_rdkit.py +++ b/testsuite/MDAnalysisTests/converters/test_rdkit.py @@ -154,7 +154,9 @@ def test_compare_mol2reader(self): universe = mda.Universe(MolFactory.mol2_mol()) mol2 = mda.Universe(mol2_molecule) assert universe.trajectory.n_frames == mol2.trajectory.n_frames - assert_equal(universe.trajectory.ts.positions, mol2.trajectory.ts.positions) + assert_equal( + universe.trajectory.ts.positions, mol2.trajectory.ts.positions + ) @requires_rdkit @@ -193,7 +195,9 @@ def test_no_atoms_attr(self): @pytest.mark.parametrize("smi", ["[H]", "C", "O", "[He]"]) def test_single_atom_mol(self, smi): - u = mda.Universe.from_smiles(smi, addHs=False, generate_coordinates=False) + u = mda.Universe.from_smiles( + smi, addHs=False, generate_coordinates=False + ) mol = u.atoms.convert_to.rdkit(inferrer=None) assert mol.GetNumAtoms() == 1 assert mol.GetAtomWithIdx(0).GetSymbol() == smi.strip("[]") @@ -236,7 +240,9 @@ def test_monomer_info(self, pdb, sel_str, atom_index): assert mda_atom.segindex == mi.GetSegmentNumber() assert mda_atom.tempfactor == mi.GetTempFactor() - @pytest.mark.parametrize("rdmol", ["mol2_mol", "smiles_mol"], indirect=True) + @pytest.mark.parametrize( + "rdmol", ["mol2_mol", "smiles_mol"], indirect=True + ) def test_identical_topology(self, rdmol): u = mda.Universe(rdmol) umol = u.atoms.convert_to("RDKIT") @@ -245,7 +251,9 @@ def test_identical_topology(self, rdmol): assert_equal(u.atoms.bonds, u2.atoms.bonds) assert_equal(u.atoms.elements, u2.atoms.elements) assert_equal(u.atoms.names, u2.atoms.names) - assert_allclose(u.atoms.positions, u2.atoms.positions, rtol=0, atol=1e-7) + assert_allclose( + u.atoms.positions, u2.atoms.positions, rtol=0, atol=1e-7 + ) def test_raise_requires_elements(self): u = mda.Universe(mol2_molecule) @@ -261,7 +269,9 @@ def test_raise_requires_elements(self): def test_warn_guess_bonds(self): u = mda.Universe(PDB_helix) - with pytest.warns(UserWarning, match="No `bonds` attribute in this AtomGroup"): + with pytest.warns( + UserWarning, match="No `bonds` attribute in this AtomGroup" + ): u.atoms.convert_to("RDKIT") def test_bonds_outside_sel(self): @@ -282,7 +292,9 @@ def test_error_no_hydrogen_implicit(self, uo2): uo2.atoms.convert_to.rdkit(inferrer=None) def test_warning_no_hydrogen_force(self, uo2): - with pytest.warns(UserWarning, match="Forcing to continue the conversion"): + with pytest.warns( + UserWarning, match="Forcing to continue the conversion" + ): uo2.atoms.convert_to.rdkit(force=True) @pytest.mark.parametrize( @@ -431,20 +443,30 @@ def test_sanitize_fail_warning(self): def test_deprecation_max_iter(self, mol2, monkeypatch): mock = Mock(wraps=atomgroup_to_mol) - monkeypatch.setattr("MDAnalysis.converters.RDKit.atomgroup_to_mol", mock) - with pytest.warns(DeprecationWarning, match="Using `max_iter` is deprecated"): + monkeypatch.setattr( + "MDAnalysis.converters.RDKit.atomgroup_to_mol", mock + ) + with pytest.warns( + DeprecationWarning, match="Using `max_iter` is deprecated" + ): mol2.atoms.convert_to.rdkit(max_iter=2) assert mock.call_args.kwargs["inferrer"].max_iter == 2 def test_deprecation_NoImplicit(self, mol2, monkeypatch): mock = Mock(wraps=atomgroup_to_mol) - monkeypatch.setattr("MDAnalysis.converters.RDKit.atomgroup_to_mol", mock) - with pytest.warns(DeprecationWarning, match="Using `NoImplicit` is deprecated"): + monkeypatch.setattr( + "MDAnalysis.converters.RDKit.atomgroup_to_mol", mock + ) + with pytest.warns( + DeprecationWarning, match="Using `NoImplicit` is deprecated" + ): mol2.atoms.convert_to.rdkit(NoImplicit=False) assert mock.call_args.kwargs["inferrer"] is None def test_deprecation_atomgroup_to_mol_NoImplicit(self, mol2): - with pytest.warns(DeprecationWarning, match="Using `NoImplicit` is deprecated"): + with pytest.warns( + DeprecationWarning, match="Using `NoImplicit` is deprecated" + ): atomgroup_to_mol(mol2.atoms, NoImplicit=False) def test_atomgroup_to_mol_unexpected_kwargs(self, mol2): @@ -469,7 +491,8 @@ def test_sanitize_mol_error(self): mol = Chem.MolFromSmiles("[NH4]", sanitize=False) with pytest.raises( Chem.AtomValenceException, - match="Explicit valence for atom # 0 N, 4, is " "greater than permitted", + match="Explicit valence for atom # 0 N, 4, is " + "greater than permitted", ): sanitize_mol(mol) @@ -502,8 +525,12 @@ def assert_isomorphic_resonance_structure(self, mol, ref): """ isomorphic = mol.HasSubstructMatch(ref) if not isomorphic: - isomorphic = bool(Chem.ResonanceMolSupplier(mol).GetSubstructMatch(ref)) - assert isomorphic, f"{Chem.MolToSmiles(ref)} != {Chem.MolToSmiles(mol)}" + isomorphic = bool( + Chem.ResonanceMolSupplier(mol).GetSubstructMatch(ref) + ) + assert ( + isomorphic + ), f"{Chem.MolToSmiles(ref)} != {Chem.MolToSmiles(mol)}" @requires_rdkit @@ -766,7 +793,9 @@ def test_warn_conjugated_max_iter(self): smi = "[C-]C=CC=CC=CC=CC=CC=C[C-]" mol = Chem.MolFromSmiles(smi) inferrer = MDAnalysisInferrer(max_iter=2) - with pytest.warns(UserWarning, match="reasonable number of iterations"): + with pytest.warns( + UserWarning, match="reasonable number of iterations" + ): inferrer._rebuild_conjugated_bonds(mol) def test_deprecation_warning_max_iter(self): @@ -846,7 +875,9 @@ def test_pdb_names(self): u = mda.Universe(PDB_helix) mol = u.atoms.convert_to.rdkit() names = u.atoms.names - rd_names = np.array([a.GetProp("_MDAnalysis_name") for a in mol.GetAtoms()]) + rd_names = np.array( + [a.GetProp("_MDAnalysis_name") for a in mol.GetAtoms()] + ) assert (names == rd_names).all() @pytest.mark.parametrize( @@ -865,7 +896,9 @@ def test_bond_stereo_not_stereoany(self, smi): assert bond.GetStereo() != Chem.BondStereo.STEREOANY def test_atom_sorter(self): - mol = Chem.MolFromSmiles("[H]-[C](-[H])-[C](-[H])-[C]-[C]-[H]", sanitize=False) + mol = Chem.MolFromSmiles( + "[H]-[C](-[H])-[C](-[H])-[C]-[C]-[H]", sanitize=False + ) # corresponding mol: C=C-C#C # atom indices: 1 3 5 6 mol.UpdatePropertyCache() @@ -881,7 +914,9 @@ def test_atom_sorter(self): [ pytest.param( True, - marks=pytest.mark.xfail(reason="Invalid charge/valence", strict=True), + marks=pytest.mark.xfail( + reason="Invalid charge/valence", strict=True + ), ), False, ], diff --git a/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py b/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py index a55ad8a449..f82d74a561 100644 --- a/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py +++ b/testsuite/MDAnalysisTests/converters/test_rdkit_parser.py @@ -120,7 +120,9 @@ def test_bond_orders(self, top, filename): expected = [bond.GetBondTypeAsDouble() for bond in filename.GetBonds()] assert top.bonds.order == expected - def test_multiple_charge_priority(self, top_gas_tripos, filename_gasteiger): + def test_multiple_charge_priority( + self, top_gas_tripos, filename_gasteiger + ): expected = np.array( [ a.GetDoubleProp("_GasteigerCharge") @@ -139,7 +141,9 @@ def test_multiple_charge_props_warning(self): top = self.parser(mol).parse() # Verify the warning assert len(w) == 1 - assert "_GasteigerCharge and _TriposPartialCharge" in str(w[-1].message) + assert "_GasteigerCharge and _TriposPartialCharge" in str( + w[-1].message + ) def test_gasteiger_charges(self, top_gasteiger, filename_gasteiger): expected = np.array( @@ -153,13 +157,18 @@ def test_gasteiger_charges(self, top_gasteiger, filename_gasteiger): def test_tripos_charges(self, top, filename): expected = np.array( - [a.GetDoubleProp("_TriposPartialCharge") for a in filename.GetAtoms()], + [ + a.GetDoubleProp("_TriposPartialCharge") + for a in filename.GetAtoms() + ], dtype=np.float32, ) assert_equal(expected, top.charges.values) def test_aromaticity(self, top, filename): - expected = np.array([atom.GetIsAromatic() for atom in filename.GetAtoms()]) + expected = np.array( + [atom.GetIsAromatic() for atom in filename.GetAtoms()] + ) assert_equal(expected, top.aromaticities.values) def test_guessed_types(self, filename): @@ -194,7 +203,9 @@ def filename(self): def test_partial_residueinfo_raise_error(self, filename): mol = Chem.RemoveHs(filename) mh = Chem.AddHs(mol) - with pytest.raises(ValueError, match="ResidueInfo is only partially available"): + with pytest.raises( + ValueError, match="ResidueInfo is only partially available" + ): mda.Universe(mh) mh = Chem.AddHs(mol, addResidueInfo=True) mda.Universe(mh) diff --git a/testsuite/MDAnalysisTests/coordinates/base.py b/testsuite/MDAnalysisTests/coordinates/base.py index c5704c990f..1568dfab87 100644 --- a/testsuite/MDAnalysisTests/coordinates/base.py +++ b/testsuite/MDAnalysisTests/coordinates/base.py @@ -71,7 +71,9 @@ def test_n_atoms(self): ) def test_numres(self): - assert_equal(self.universe.atoms.n_residues, 214, "wrong number of residues") + assert_equal( + self.universe.atoms.n_residues, 214, "wrong number of residues" + ) def test_n_frames(self): assert_equal( @@ -81,13 +83,16 @@ def test_n_frames(self): ) def test_time(self): - assert_equal(self.universe.trajectory.time, 0.0, "wrong time of the frame") + assert_equal( + self.universe.trajectory.time, 0.0, "wrong time of the frame" + ) def test_frame(self): assert_equal( self.universe.trajectory.frame, 0, - "wrong frame number (0-based, should be 0 for single frame " "readers)", + "wrong frame number (0-based, should be 0 for single frame " + "readers)", ) def test_frame_index_0(self): @@ -201,7 +206,9 @@ def __init__(self): [2**8], # frame 4 = 4ps = step 8 ] self.aux_highf_n_steps = 10 - self.aux_highf_all_data = [[2**i] for i in range(self.aux_highf_n_steps)] + self.aux_highf_all_data = [ + [2**i] for i in range(self.aux_highf_n_steps) + ] self.aux_offset_by = 0.25 @@ -232,7 +239,9 @@ def __init__(self): self.jump_to_frame.aux.lowf = self.aux_lowf_data[3] self.jump_to_frame.aux.highf = self.aux_highf_data[3] - self.dimensions = np.array([81.1, 82.2, 83.3, 75, 80, 85], dtype=np.float32) + self.dimensions = np.array( + [81.1, 82.2, 83.3, 75, 80, 85], dtype=np.float32 + ) self.dimensions_second_frame = np.array( [82.1, 83.2, 84.3, 75.1, 80.1, 85.1], dtype=np.float32 ) @@ -276,7 +285,9 @@ def reader(ref): @pytest.fixture() def transformed(ref): transformed = ref.reader(ref.trajectory) - transformed.add_transformations(translate([1, 1, 1]), translate([0, 0, 0.33])) + transformed.add_transformations( + translate([1, 1, 1]), translate([0, 0, 0.33]) + ) return transformed def test_n_atoms(self, ref, reader): @@ -287,7 +298,9 @@ def test_n_frames(self, ref, reader): def test_first_frame(self, ref, reader): reader.rewind() - assert_timestep_almost_equal(reader.ts, ref.first_frame, decimal=ref.prec) + assert_timestep_almost_equal( + reader.ts, ref.first_frame, decimal=ref.prec + ) def test_double_close(self, reader): reader.close() @@ -377,7 +390,8 @@ def test_iter_auxiliary(self, ref, reader): assert_almost_equal( auxstep.data, ref.aux_highf_all_data[i], - err_msg="Auxiliary data does not match for " "step {}".format(i), + err_msg="Auxiliary data does not match for " + "step {}".format(i), ) def test_get_aux_attribute(self, ref, reader): @@ -400,7 +414,8 @@ def test_iter_as_aux_cutoff(self, ref, reader): assert_equal( num_frames, 0, - "iter_as_aux should iterate over 0 frames," " not {}".format(num_frames), + "iter_as_aux should iterate over 0 frames," + " not {}".format(num_frames), ) def test_reload_auxiliaries_from_description(self, ref, reader): @@ -438,7 +453,9 @@ def test_transformations_iter(self, ref, transformed): v2 = np.float32((0, 0, 0.33)) for i, ts in enumerate(transformed): idealcoords = ref.iter_ts(i).positions + v1 + v2 - assert_array_almost_equal(ts.positions, idealcoords, decimal=ref.prec) + assert_array_almost_equal( + ts.positions, idealcoords, decimal=ref.prec + ) def test_transformations_2iter(self, ref, transformed): # Are the transformations applied and @@ -448,7 +465,9 @@ def test_transformations_2iter(self, ref, transformed): idealcoords = [] for i, ts in enumerate(transformed): idealcoords.append(ref.iter_ts(i).positions + v1 + v2) - assert_array_almost_equal(ts.positions, idealcoords[i], decimal=ref.prec) + assert_array_almost_equal( + ts.positions, idealcoords[i], decimal=ref.prec + ) for i, ts in enumerate(transformed): assert_almost_equal(ts.positions, idealcoords[i], decimal=ref.prec) @@ -459,7 +478,9 @@ def test_transformations_slice(self, ref, transformed): v2 = np.float32((0, 0, 0.33)) for i, ts in enumerate(transformed[2:3:1]): idealcoords = ref.iter_ts(ts.frame).positions + v1 + v2 - assert_array_almost_equal(ts.positions, idealcoords, decimal=ref.prec) + assert_array_almost_equal( + ts.positions, idealcoords, decimal=ref.prec + ) def test_transformations_switch_frame(self, ref, transformed): # This test checks if the transformations are applied and if the coordinates @@ -515,7 +536,9 @@ def test_transformations_copy(self, ref, transformed): ) for i, ts in enumerate(new): ideal_coords = ref.iter_ts(i).positions + v1 + v2 - assert_array_almost_equal(ts.positions, ideal_coords, decimal=ref.prec) + assert_array_almost_equal( + ts.positions, ideal_coords, decimal=ref.prec + ) def test_add_another_transformations_raises_ValueError(self, transformed): # After defining the transformations, the workflow cannot be changed @@ -525,7 +548,9 @@ def test_add_another_transformations_raises_ValueError(self, transformed): def test_pickle_reader(self, reader): reader_p = pickle.loads(pickle.dumps(reader)) assert_equal(len(reader), len(reader_p)) - assert_equal(reader.ts, reader_p.ts, "Timestep is changed after pickling") + assert_equal( + reader.ts, reader_p.ts, "Timestep is changed after pickling" + ) reader_p_p = pickle.loads(pickle.dumps(reader_p)) assert_equal(len(reader), len(reader_p_p)) assert_equal( @@ -559,7 +584,9 @@ def test_frame_collect_all_same(self, reader): for array in collected_ts: assert_allclose(array, collected_ts[0]) - @pytest.mark.parametrize("order", ("fac", "fca", "afc", "acf", "caf", "cfa")) + @pytest.mark.parametrize( + "order", ("fac", "fca", "afc", "acf", "caf", "cfa") + ) def test_timeseries_shape(self, reader, order): timeseries = reader.timeseries(order=order) a_index = order.index("a") @@ -601,7 +628,9 @@ def test_timeseries_empty_asel(self, reader): UserWarning, match="Empty string to select atoms, empty group returned.", ): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms(None) + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( + None + ) with pytest.raises(ValueError, match="Timeseries requires at least"): reader.timeseries(asel=atoms) @@ -610,23 +639,33 @@ def test_timeseries_empty_atomgroup(self, reader): UserWarning, match="Empty string to select atoms, empty group returned.", ): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms(None) + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( + None + ) with pytest.raises(ValueError, match="Timeseries requires at least"): reader.timeseries(atomgroup=atoms) def test_timeseries_asel_warns_deprecation(self, reader): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms("index 1") + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( + "index 1" + ) with pytest.warns(DeprecationWarning, match="asel argument to"): timeseries = reader.timeseries(asel=atoms, order="fac") def test_timeseries_atomgroup(self, reader): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms("index 1") + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( + "index 1" + ) timeseries = reader.timeseries(atomgroup=atoms, order="fac") def test_timeseries_atomgroup_asel_mutex(self, reader): - atoms = mda.Universe(reader.filename, to_guess=()).select_atoms("index 1") + atoms = mda.Universe(reader.filename, to_guess=()).select_atoms( + "index 1" + ) with pytest.raises(ValueError, match="Cannot provide both"): - timeseries = reader.timeseries(atomgroup=atoms, asel=atoms, order="fac") + timeseries = reader.timeseries( + atomgroup=atoms, asel=atoms, order="fac" + ) class MultiframeReaderTest(BaseReaderTest): @@ -729,7 +768,9 @@ def test_pickle_last_ts_reader(self, reader): len(reader_p), "Last timestep is changed after pickling", ) - assert_equal(reader.ts, reader_p.ts, "Last timestep is changed after pickling") + assert_equal( + reader.ts, reader_p.ts, "Last timestep is changed after pickling" + ) class BaseWriterTest(object): @@ -919,7 +960,9 @@ def assert_timestep_almost_equal(A, B, decimal=6, verbose=True): if A.has_forces != B.has_forces: raise AssertionError( "Only one Timestep has forces:" - "A.has_forces = {}, B.has_forces = {}".format(A.has_forces, B.has_forces) + "A.has_forces = {}, B.has_forces = {}".format( + A.has_forces, B.has_forces + ) ) if A.has_forces: assert_array_almost_equal( diff --git a/testsuite/MDAnalysisTests/coordinates/reference.py b/testsuite/MDAnalysisTests/coordinates/reference.py index 8452bfab35..8d43a9f925 100644 --- a/testsuite/MDAnalysisTests/coordinates/reference.py +++ b/testsuite/MDAnalysisTests/coordinates/reference.py @@ -228,7 +228,9 @@ class RefTRZ(object): class RefLAMMPSData(object): filename = LAMMPSdata n_atoms = 18364 - pos_atom1 = np.array([11.89985657, 48.4455719, 19.09719849], dtype=np.float32) + pos_atom1 = np.array( + [11.89985657, 48.4455719, 19.09719849], dtype=np.float32 + ) vel_atom1 = np.array( [-0.005667593, 0.00791380978, -0.00300779533], dtype=np.float32 ) @@ -254,11 +256,15 @@ class RefLAMMPSDataDCD(object): class RefLAMMPSDataMini(object): filename = LAMMPSdata_mini n_atoms = 1 - pos_atom1 = np.array([11.89985657, 48.4455719, 19.09719849], dtype=np.float32) + pos_atom1 = np.array( + [11.89985657, 48.4455719, 19.09719849], dtype=np.float32 + ) vel_atom1 = np.array( [-0.005667593, 0.00791380978, -0.00300779533], dtype=np.float32 ) - dimensions = np.array([60.0, 50.0, 30.0, 90.0, 90.0, 90.0], dtype=np.float32) + dimensions = np.array( + [60.0, 50.0, 30.0, 90.0, 90.0, 90.0], dtype=np.float32 + ) class RefLAMMPSDataAdditionalColumns(object): diff --git a/testsuite/MDAnalysisTests/coordinates/test_chainreader.py b/testsuite/MDAnalysisTests/coordinates/test_chainreader.py index a54a92681e..4614e3e4d1 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_chainreader.py +++ b/testsuite/MDAnalysisTests/coordinates/test_chainreader.py @@ -82,7 +82,9 @@ def test_next_trajectory(self, universe): assert_equal(universe.trajectory.ts.frame, 1, "loading frame 2") def test_n_atoms(self, universe): - assert_equal(universe.trajectory.n_atoms, 3341, "wrong number of atoms") + assert_equal( + universe.trajectory.n_atoms, 3341, "wrong number of atoms" + ) def test_n_frames(self, universe): assert_equal( @@ -159,7 +161,9 @@ def test_write_dcd(self, universe, tmpdir): ts_orig._pos, ts_new._pos, self.prec, - err_msg="Coordinates disagree at frame {0:d}".format(ts_orig.frame), + err_msg="Coordinates disagree at frame {0:d}".format( + ts_orig.frame + ), ) def test_transform_iteration(self, universe, transformed): @@ -189,18 +193,26 @@ def test_transform_switch(self, universe, transformed): vector = np.float32([10, 10, 10]) # grab a frame: ref = universe.trajectory[2].positions + vector - assert_almost_equal(transformed.trajectory[2].positions, ref, decimal=6) + assert_almost_equal( + transformed.trajectory[2].positions, ref, decimal=6 + ) # now switch to another frame newref = universe.trajectory[10].positions + vector - assert_almost_equal(transformed.trajectory[10].positions, newref, decimal=6) + assert_almost_equal( + transformed.trajectory[10].positions, newref, decimal=6 + ) # what happens when we comeback to the previous frame? - assert_almost_equal(transformed.trajectory[2].positions, ref, decimal=6) + assert_almost_equal( + transformed.trajectory[2].positions, ref, decimal=6 + ) def test_transfrom_rewind(self, universe, transformed): vector = np.float32([10, 10, 10]) ref = universe.trajectory[0].positions + vector transformed.trajectory.rewind() - assert_almost_equal(transformed.trajectory.ts.positions, ref, decimal=6) + assert_almost_equal( + transformed.trajectory.ts.positions, ref, decimal=6 + ) class TestChainReaderCommonDt(object): @@ -230,7 +242,9 @@ class TestChainReaderFormats(object): """Test of ChainReader with explicit formats (Issue 76).""" def test_set_all_format_tuples(self): - universe = mda.Universe(GRO, [(PDB, "pdb"), (XTC, "xtc"), (TRR, "trr")]) + universe = mda.Universe( + GRO, [(PDB, "pdb"), (XTC, "xtc"), (TRR, "trr")] + ) assert universe.trajectory.n_frames == 21 assert_equal(universe.trajectory.filenames, [PDB, XTC, TRR]) @@ -376,7 +390,9 @@ def __init__(self, seq, n_frames, order): ) def test_order(self, seq_info, tmpdir, fmt): folder = str(tmpdir) - utop, fnames = build_trajectories(folder, sequences=seq_info.seq, fmt=fmt) + utop, fnames = build_trajectories( + folder, sequences=seq_info.seq, fmt=fmt + ) u = mda.Universe(utop._topology, fnames, continuous=True, to_guess=()) assert u.trajectory.n_frames == seq_info.n_frames for i, ts in enumerate(u.trajectory): @@ -441,8 +457,12 @@ def test_easy_trigger_warning(self, tmpdir): # TODO: remove when we no longer have a dependency # that still imports six if sys.version_info >= (3, 10): - warnings.filterwarnings(action="ignore", category=ImportWarning) - mda.Universe(utop._topology, fnames, continuous=True, to_guess=()) + warnings.filterwarnings( + action="ignore", category=ImportWarning + ) + mda.Universe( + utop._topology, fnames, continuous=True, to_guess=() + ) def test_single_frames(self, tmpdir): folder = str(tmpdir) diff --git a/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py b/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py index fd489977fe..a556414de3 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py +++ b/testsuite/MDAnalysisTests/coordinates/test_chemfiles.py @@ -54,7 +54,9 @@ def test_version_check(version, monkeypatch): ChemfilesWriter("") -@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") +@pytest.mark.skipif( + not check_chemfiles_version(), reason="Wrong version of chemfiles" +) class TestChemfileXYZ(MultiframeReaderTest): @staticmethod @pytest.fixture @@ -97,7 +99,9 @@ def __init__(self): self.dimensions = None -@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") +@pytest.mark.skipif( + not check_chemfiles_version(), reason="Wrong version of chemfiles" +) class TestChemfilesReader(MultiframeReaderTest): @staticmethod @pytest.fixture() @@ -142,7 +146,9 @@ def test_copy(self, ref): assert_allclose(original.ts.positions, copy.ts.positions) -@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") +@pytest.mark.skipif( + not check_chemfiles_version(), reason="Wrong version of chemfiles" +) class TestChemfilesWriter(BaseWriterTest): @staticmethod @pytest.fixture() @@ -159,7 +165,9 @@ def test_no_extension_raises(self, ref): ref.writer("foo") -@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") +@pytest.mark.skipif( + not check_chemfiles_version(), reason="Wrong version of chemfiles" +) class TestChemfiles(object): def test_read_chemfiles_format(self): u = mda.Universe( @@ -183,7 +191,9 @@ def test_changing_system_size(self, tmpdir): with open(outfile, "w") as fd: fd.write(VARYING_XYZ) - u = mda.Universe(outfile, format="chemfiles", topology_format="XYZ") + u = mda.Universe( + outfile, format="chemfiles", topology_format="XYZ" + ) with pytest.raises(IOError): u.trajectory._read_next_timestep() @@ -194,7 +204,9 @@ def test_wrong_open_mode(self): def check_topology(self, reference, file): u = mda.Universe(reference) - atoms = set([(atom.name, atom.type, atom.record_type) for atom in u.atoms]) + atoms = set( + [(atom.name, atom.type, atom.record_type) for atom in u.atoms] + ) bonds = set([(bond.atoms[0].ix, bond.atoms[1].ix) for bond in u.bonds]) check = mda.Universe(file) diff --git a/testsuite/MDAnalysisTests/coordinates/test_copying.py b/testsuite/MDAnalysisTests/coordinates/test_copying.py index c8d32ac721..6a6cd86590 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_copying.py +++ b/testsuite/MDAnalysisTests/coordinates/test_copying.py @@ -288,7 +288,9 @@ def test_timestep_copied(ref_reader): assert new.ts.positions.dtype == np.float32 -@pytest.mark.skipif(shares_memory == False, reason="old numpy lacked shares_memory") +@pytest.mark.skipif( + shares_memory == False, reason="old numpy lacked shares_memory" +) def test_positions_share_memory(original_and_copy): # check that the memory in Timestep objects is unique original, copy = original_and_copy diff --git a/testsuite/MDAnalysisTests/coordinates/test_crd.py b/testsuite/MDAnalysisTests/coordinates/test_crd.py index edbd4886b9..be68d82eae 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_crd.py +++ b/testsuite/MDAnalysisTests/coordinates/test_crd.py @@ -41,7 +41,9 @@ def u(self): def outfile(self, tmpdir): return os.path.join(str(tmpdir), "test.crd") - @pytest.mark.parametrize("testfile", ["test.crd", "test.crd.bz2", "test.crd.gz"]) + @pytest.mark.parametrize( + "testfile", ["test.crd", "test.crd.bz2", "test.crd.gz"] + ) def test_write_atoms(self, u, testfile, tmpdir): # Test that written file when read gives same coordinates with tmpdir.as_cwd(): @@ -135,4 +137,6 @@ def test_write(self, missing_attr, tmpdir): for attr in attrs: assert_equal(getattr(u.atoms, attr), getattr(u2.atoms, attr)) # Check missing attr is as expected - assert_equal(getattr(u2.atoms, missing_attr), self.req_attrs[missing_attr]) + assert_equal( + getattr(u2.atoms, missing_attr), self.req_attrs[missing_attr] + ) diff --git a/testsuite/MDAnalysisTests/coordinates/test_dcd.py b/testsuite/MDAnalysisTests/coordinates/test_dcd.py index 598eb89e40..0eea9cb4cd 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_dcd.py +++ b/testsuite/MDAnalysisTests/coordinates/test_dcd.py @@ -210,7 +210,9 @@ def test_array_like(universe_dcd, array_like): assert_array_equal(frames, ar) -@pytest.mark.parametrize("indices", ([0, 4, 2, 3, 0, 1], [0, 0, 1, 1, 2, 1, 1])) +@pytest.mark.parametrize( + "indices", ([0, 4, 2, 3, 0, 1], [0, 0, 1, 1, 2, 1, 1]) +) def test_list_indices(universe_dcd, indices): frames = [ts.frame for ts in universe_dcd.trajectory[indices]] assert_array_equal(frames, indices) @@ -266,7 +268,9 @@ def test_timeseries_order(order, shape, universe_dcd): assert x.shape == shape -@pytest.mark.parametrize("indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]]) +@pytest.mark.parametrize( + "indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]] +) def test_timeseries_atomindices(indices, universe_dcd): allframes = universe_dcd.trajectory.timeseries(order="afc") asel = universe_dcd.atoms[indices] @@ -352,7 +356,9 @@ def test_other_writer(universe_dcd, tmpdir, ext, decimal): decimal, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame {} (orig) vs {} (written)".format(orig_ts.frame, written_ts.frame), + "frame {} (orig) vs {} (written)".format( + orig_ts.frame, written_ts.frame + ), ) @@ -499,7 +505,8 @@ def test_ts_time(universe): u = universe header = u.trajectory._file.header ref_times = [ - (ts.frame + header["istart"] / header["nsavc"]) * ts.dt for ts in u.trajectory + (ts.frame + header["istart"] / header["nsavc"]) * ts.dt + for ts in u.trajectory ] times = [ts.time for ts in u.trajectory] assert_almost_equal(times, ref_times, decimal=5) diff --git a/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py b/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py index 786a362e2f..63d0a09464 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py +++ b/testsuite/MDAnalysisTests/coordinates/test_dlpoly.py @@ -58,7 +58,9 @@ def test_read_unitcell(self, ts): [0.0000000000, 0.0000000000, 18.6960000000], ] ) - assert_allclose(ts.dimensions, mda.coordinates.core.triclinic_box(*ref)) + assert_allclose( + ts.dimensions, mda.coordinates.core.triclinic_box(*ref) + ) def test_positions(self, ts): ref = np.array([-7.608595309, -7.897790000, -7.892053559]) @@ -218,7 +220,9 @@ def test_unitcell(self, u): ] ) for ts, r in zip(u.trajectory, [ref1, ref2, ref3]): - assert_allclose(ts.dimensions, mda.coordinates.core.triclinic_box(*r)) + assert_allclose( + ts.dimensions, mda.coordinates.core.triclinic_box(*r) + ) class TestDLPolyHistory(_DLHistory): diff --git a/testsuite/MDAnalysisTests/coordinates/test_dms.py b/testsuite/MDAnalysisTests/coordinates/test_dms.py index 820703761f..e4d9ac1ee6 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_dms.py +++ b/testsuite/MDAnalysisTests/coordinates/test_dms.py @@ -67,7 +67,9 @@ def test_coords_atom_0(self, universe): assert_equal(universe.atoms[0].position, coords_0) def test_n_frames(self, universe): - assert_equal(universe.trajectory.n_frames, 1, "wrong number of frames in pdb") + assert_equal( + universe.trajectory.n_frames, 1, "wrong number of frames in pdb" + ) def test_time(self, universe): assert_equal(universe.trajectory.time, 0.0, "wrong time of the frame") @@ -76,7 +78,8 @@ def test_frame(self, universe): assert_equal( universe.trajectory.frame, 0, - "wrong frame number " "(0-based, should be 0 for single frame readers)", + "wrong frame number " + "(0-based, should be 0 for single frame readers)", ) def test_frame_index_0(self, universe): diff --git a/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py b/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py index 187c9c5cea..f1ec55b191 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py +++ b/testsuite/MDAnalysisTests/coordinates/test_fhiaims.py @@ -69,7 +69,9 @@ class RefFHIAIMS(object): filename, trajectory, topology = [FHIAIMS] * 3 reader, writer = FHIAIMSReader, FHIAIMSWriter pos_atom1 = np.asarray([6.861735, 2.103823, 37.753513], dtype=np.float32) - dimensions = np.asarray([18.6, 18.6, 55.8, 90.0, 90.0, 90.0], dtype=np.float32) + dimensions = np.asarray( + [18.6, 18.6, 55.8, 90.0, 90.0, 90.0], dtype=np.float32 + ) n_atoms = 6 n_frames = 1 time = 0.0 @@ -85,9 +87,7 @@ class TestFHIAIMSReader(object): @pytest.fixture(scope="class") def bad_input_missing_periodicity(self): - buffer = ( - "lattice_vector 1.0 0.0 0.0\nlattice_vector 0.0 1.0 0.0\natom 0.1 0.1 0.1 H" - ) + buffer = "lattice_vector 1.0 0.0 0.0\nlattice_vector 0.0 1.0 0.0\natom 0.1 0.1 0.1 H" return StringIO(buffer) @pytest.fixture(scope="class") @@ -162,9 +162,13 @@ def test_n_frames(self, ref, universe): ) def test_time(self, ref, universe): - assert_equal(ref.time, universe.trajectory.time, "wrong time of the frame") + assert_equal( + ref.time, universe.trajectory.time, "wrong time of the frame" + ) - def test_bad_input_missing_periodicity(self, bad_input_missing_periodicity): + def test_bad_input_missing_periodicity( + self, bad_input_missing_periodicity + ): with pytest.raises(ValueError, match="Found partial periodicity"): u = mda.Universe(bad_input_missing_periodicity, format="FHIAIMS") @@ -175,17 +179,25 @@ def test_bad_input_relative_positions_no_box( ValueError, match="Found relative coordinates in FHI-AIMS file without lattice info", ): - u = mda.Universe(bad_input_relative_positions_no_box, format="FHIAIMS") + u = mda.Universe( + bad_input_relative_positions_no_box, format="FHIAIMS" + ) def test_bad_input_missing_velocity(self, bad_input_missing_velocity): - with pytest.raises(ValueError, match="Found incorrect number of velocity tags"): + with pytest.raises( + ValueError, match="Found incorrect number of velocity tags" + ): u = mda.Universe(bad_input_missing_velocity, format="FHIAIMS") - def test_bad_input_velocity_wrong_position(self, bad_input_velocity_wrong_position): + def test_bad_input_velocity_wrong_position( + self, bad_input_velocity_wrong_position + ): with pytest.raises( ValueError, match="Non-conforming line .velocity must follow" ): - u = mda.Universe(bad_input_velocity_wrong_position, format="FHIAIMS") + u = mda.Universe( + bad_input_velocity_wrong_position, format="FHIAIMS" + ) def test_bad_input_wrong_input_line(self, bad_input_wrong_input_line): with pytest.raises(ValueError, match="Non-conforming line"): @@ -200,7 +212,9 @@ def test_good_input_with_velocity(self, good_input_with_velocity): "FHIAIMSReader failed to read velocities properly", ) - def test_mixed_units(self, good_input_natural_units, good_input_mixed_units): + def test_mixed_units( + self, good_input_natural_units, good_input_mixed_units + ): u_natural = mda.Universe(good_input_natural_units, format="FHIAIMS") u_mixed = mda.Universe(good_input_mixed_units, format="FHIAIMS") print(u_natural.atoms.positions) @@ -220,7 +234,9 @@ class TestFHIAIMSWriter(BaseWriterTest): @pytest.fixture def outfile(self, tmpdir): return str( - tmpdir.mkdir("FHIAIMSWriter").join("primitive-fhiaims-writer" + self.ext) + tmpdir.mkdir("FHIAIMSWriter").join( + "primitive-fhiaims-writer" + self.ext + ) ) def test_writer(self, universe, outfile): @@ -263,7 +279,9 @@ def test_writer_with_n_atoms_none(self, good_input_natural_units, outfile): assert line.startswith( "atom" ), "Line written incorrectly with FHIAIMSWriter" - assert line.endswith("H"), "Line written incorrectly with FHIAIMSWriter" + assert line.endswith( + "H" + ), "Line written incorrectly with FHIAIMSWriter" line = np.asarray(line.split()[1:-1], dtype=np.float32) assert_almost_equal( line, diff --git a/testsuite/MDAnalysisTests/coordinates/test_gms.py b/testsuite/MDAnalysisTests/coordinates/test_gms.py index 4b7ee7c7e3..355e0658ba 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_gms.py +++ b/testsuite/MDAnalysisTests/coordinates/test_gms.py @@ -78,7 +78,9 @@ def test_next(self, u): assert_equal(u.trajectory.ts.frame, 1, "loading frame 1") def test_dt(self, u): - assert_almost_equal(u.trajectory.dt, 1.0, 4, err_msg="wrong timestep dt") + assert_almost_equal( + u.trajectory.dt, 1.0, 4, err_msg="wrong timestep dt" + ) def test_step5distances(self, u): assert_almost_equal( diff --git a/testsuite/MDAnalysisTests/coordinates/test_gro.py b/testsuite/MDAnalysisTests/coordinates/test_gro.py index 5f3d7f9123..c307bdc8ca 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_gro.py +++ b/testsuite/MDAnalysisTests/coordinates/test_gro.py @@ -61,7 +61,9 @@ def universe(self): def test_load_gro(self, universe): U = universe - assert_equal(len(U.atoms), self.ref_n_atoms, "load Universe from small GRO") + assert_equal( + len(U.atoms), self.ref_n_atoms, "load Universe from small GRO" + ) assert_equal( U.atoms.select_atoms("resid 150 and name HA2").atoms[0], U.atoms[self.ref_E151HA2_index], @@ -328,7 +330,9 @@ def reader(ref): @pytest.fixture(scope="class") def transformed(ref): transformed = ref.reader(ref.trajectory, convert_units=False) - transformed.add_transformations(translate([1, 1, 1]), translate([0, 0, 0.33])) + transformed.add_transformations( + translate([1, 1, 1]), translate([0, 0, 0.33]) + ) return transformed @@ -420,7 +424,9 @@ def test_writer_large(self, ref, tmpdir): u.atoms.write(outfile) with open(outfile, "rt") as mda_output: - with mda.lib.util.anyopen(ref.topology, "rt") as expected_output: + with mda.lib.util.anyopen( + ref.topology, "rt" + ) as expected_output: produced_lines = mda_output.readlines()[1:] expected_lines = expected_output.readlines()[1:] assert_equal( @@ -525,7 +531,9 @@ def test_multiframe_gro(): # for now, single frame read assert len(u.trajectory) == 1 - assert_equal(u.dimensions, np.array([100, 100, 100, 90, 90, 90], dtype=np.float32)) + assert_equal( + u.dimensions, np.array([100, 100, 100, 90, 90, 90], dtype=np.float32) + ) def test_huge_box_gro(): diff --git a/testsuite/MDAnalysisTests/coordinates/test_h5md.py b/testsuite/MDAnalysisTests/coordinates/test_h5md.py index 3587de1ef1..1524ca7f62 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_h5md.py +++ b/testsuite/MDAnalysisTests/coordinates/test_h5md.py @@ -311,19 +311,24 @@ def test_jump_last_frame(self, universe): @pytest.mark.parametrize("start, stop, step", ((0, 2, 1), (1, 2, 1))) def test_slice(self, universe, start, stop, step): frames = [ - universe.trajectory.ts.frame for ts in universe.trajectory[start:stop:step] + universe.trajectory.ts.frame + for ts in universe.trajectory[start:stop:step] ] assert_equal(frames, np.arange(start, stop, step)) @pytest.mark.parametrize("array_like", [list, np.array]) def test_array_like(self, universe, array_like): array = array_like([0, 2]) - frames = [universe.trajectory.ts.frame for ts in universe.trajectory[array]] + frames = [ + universe.trajectory.ts.frame for ts in universe.trajectory[array] + ] assert_equal(frames, array) def test_list_indices(self, universe): indices = [0, 1, 2, 1, 2, 2, 0] - frames = [universe.trajectory.ts.frame for ts in universe.trajectory[indices]] + frames = [ + universe.trajectory.ts.frame for ts in universe.trajectory[indices] + ] assert_equal(frames, indices) @pytest.mark.parametrize( @@ -353,8 +358,12 @@ def test_unknown_unit(self, h5md_file, outfile, dset): with h5py.File(outfile, "w") as g: f.copy(source="particles", dest=g) f.copy(source="h5md", dest=g) - g["particles" "/trajectory" f"/{dset}"].attrs["unit"] = "random string" - with pytest.raises(RuntimeError, match=" is not recognized by H5MDReader."): + g["particles" "/trajectory" f"/{dset}"].attrs[ + "unit" + ] = "random string" + with pytest.raises( + RuntimeError, match=" is not recognized by H5MDReader." + ): u = mda.Universe(TPR_xvf, outfile) def test_length_unit_from_box(self, h5md_file, universe, outfile): @@ -365,10 +374,14 @@ def test_length_unit_from_box(self, h5md_file, universe, outfile): del g["particles/trajectory/position"] ref_u = universe uw = mda.Universe(TPR_xvf, outfile) - assert_equal(ref_u.trajectory.units["length"], uw.trajectory.units["length"]) + assert_equal( + ref_u.trajectory.units["length"], uw.trajectory.units["length"] + ) for ref_ts, new_ts in zip(ref_u.trajectory, uw.trajectory): assert_equal(ref_ts.dimensions, new_ts.dimensions) - assert_equal(ref_ts.triclinic_dimensions, new_ts.triclinic_dimensions) + assert_equal( + ref_ts.triclinic_dimensions, new_ts.triclinic_dimensions + ) @pytest.mark.parametrize("group", ("position", "velocity", "force")) def test_changing_n_atoms(self, h5md_file, outfile, group): @@ -393,7 +406,9 @@ def test_2D_box(self, h5md_file, outfile): g["particles/trajectory" "/box/edges"].create_dataset( "value", data=new_box ) - with pytest.raises(ValueError, match="MDAnalysis only supports 3-dimensional"): + with pytest.raises( + ValueError, match="MDAnalysis only supports 3-dimensional" + ): u = mda.Universe(TPR_xvf, outfile) def test_box_vector(self, h5md_file, outfile): @@ -429,7 +444,9 @@ def test_no_groups(self, h5md_file, outfile): del g["particles/trajectory/position"] del g["particles/trajectory/velocity"] del g["particles/trajectory/force"] - with pytest.raises(NoDataError, match="Provide at least a position, velocity"): + with pytest.raises( + NoDataError, match="Provide at least a position, velocity" + ): u = mda.Universe(TPR_xvf, outfile) def test_no_convert_units(self, h5md_file, outfile): @@ -455,7 +472,9 @@ def test_no_units_but_convert_units_true_error(self, h5md_file, outfile): del g["particles/trajectory"][name]["value"].attrs["unit"] del g["particles/trajectory/position/time"].attrs["unit"] del g["particles/trajectory/box/edges/value"].attrs["unit"] - with pytest.raises(ValueError, match="H5MD file must have readable units if"): + with pytest.raises( + ValueError, match="H5MD file must have readable units if" + ): u = mda.Universe(TPR_xvf, outfile, convert_units=True) @pytest.mark.xfail(reason="Issue #2884") @@ -564,7 +583,9 @@ def outtop(self, tmpdir): (0.5, IOError, "H5MDWriter: Timestep does not have"), ), ) - def test_n_atoms_errors(self, universe, Writer, outfile, scalar, error, match): + def test_n_atoms_errors( + self, universe, Writer, outfile, scalar, error, match + ): n_atoms = universe.atoms.n_atoms * scalar with pytest.raises(error, match=match): with Writer(outfile, n_atoms) as W: @@ -644,7 +665,9 @@ def test_has_property(self, universe, Writer, outfile): (False, False, False), ), ) - def test_write_trajectory(self, universe, Writer, outfile, pos, vel, force): + def test_write_trajectory( + self, universe, Writer, outfile, pos, vel, force + ): try: with Writer( outfile, @@ -662,21 +685,31 @@ def test_write_trajectory(self, universe, Writer, outfile, pos, vel, force): # check the trajectory contents match reference universes for ts, ref_ts in zip(uw.trajectory, universe.trajectory): - assert_almost_equal(ts.dimensions, ref_ts.dimensions, self.prec) + assert_almost_equal( + ts.dimensions, ref_ts.dimensions, self.prec + ) if pos: assert_almost_equal(ts._pos, ref_ts._pos, self.prec) else: - with pytest.raises(NoDataError, match="This Timestep has no"): + with pytest.raises( + NoDataError, match="This Timestep has no" + ): getattr(ts, "positions") if vel: - assert_almost_equal(ts._velocities, ref_ts._velocities, self.prec) + assert_almost_equal( + ts._velocities, ref_ts._velocities, self.prec + ) else: - with pytest.raises(NoDataError, match="This Timestep has no"): + with pytest.raises( + NoDataError, match="This Timestep has no" + ): getattr(ts, "velocities") if force: assert_almost_equal(ts._forces, ref_ts._forces, self.prec) else: - with pytest.raises(NoDataError, match="This Timestep has no"): + with pytest.raises( + NoDataError, match="This Timestep has no" + ): getattr(ts, "forces") # when (False, False, False) @@ -710,10 +743,14 @@ def test_write_AtomGroup_with(self, universe, outfile, outtop, Writer): for orig_ts, written_ts in zip(universe.trajectory, uw.trajectory): assert_almost_equal(ca.positions, caw.positions, self.prec) assert_almost_equal(orig_ts.time, written_ts.time, self.prec) - assert_almost_equal(written_ts.dimensions, orig_ts.dimensions, self.prec) + assert_almost_equal( + written_ts.dimensions, orig_ts.dimensions, self.prec + ) @pytest.mark.parametrize("frames, n_frames", ((None, 1), ("all", 3))) - def test_ag_write(self, universe, outfile, outtop, Writer, frames, n_frames): + def test_ag_write( + self, universe, outfile, outtop, Writer, frames, n_frames + ): """test to write with ag.write()""" ca = universe.select_atoms("protein and name CA") ca.write(outtop) @@ -727,7 +764,9 @@ def test_ag_write(self, universe, outfile, outtop, Writer, frames, n_frames): for orig_ts, written_ts in zip(universe.trajectory, uw.trajectory): assert_almost_equal(ca.positions, caw.positions, self.prec) assert_almost_equal(orig_ts.time, written_ts.time, self.prec) - assert_almost_equal(written_ts.dimensions, orig_ts.dimensions, self.prec) + assert_almost_equal( + written_ts.dimensions, orig_ts.dimensions, self.prec + ) @pytest.mark.parametrize( "timeunit, lengthunit, velocityunit, forceunit", @@ -814,8 +853,12 @@ def test_no_units_w_convert_true(self, universe_no_units, outfile, Writer): for ts in universe_no_units.trajectory: W.write(universe_no_units) - def test_no_units_w_convert_false(self, universe_no_units, outfile, Writer): - with Writer(outfile, universe_no_units.atoms.n_atoms, convert_units=False) as W: + def test_no_units_w_convert_false( + self, universe_no_units, outfile, Writer + ): + with Writer( + outfile, universe_no_units.atoms.n_atoms, convert_units=False + ) as W: for ts in universe_no_units.trajectory: W.write(universe_no_units) @@ -825,7 +868,9 @@ def test_no_units_w_convert_false(self, universe_no_units, outfile, Writer): @pytest.mark.parametrize("convert_units", (True, False)) def test_convert_units(self, universe, outfile, Writer, convert_units): - with Writer(outfile, universe.atoms.n_atoms, convert_units=convert_units) as W: + with Writer( + outfile, universe.atoms.n_atoms, convert_units=convert_units + ) as W: for ts in universe.trajectory: W.write(universe) @@ -835,7 +880,9 @@ def test_convert_units(self, universe, outfile, Writer, convert_units): for u1, u2 in zip(ref_units, uw_units): assert_equal(u1, u2) - @pytest.mark.parametrize("chunks", ((3, 1000, 1), (1, 1000, 3), (100, 100, 3))) + @pytest.mark.parametrize( + "chunks", ((3, 1000, 1), (1, 1000, 3), (100, 100, 3)) + ) def test_write_chunks(self, universe, outfile, Writer, chunks): with Writer(outfile, universe.atoms.n_atoms, chunks=chunks) as W: for ts in universe.trajectory: @@ -877,7 +924,9 @@ def test_write_chunks_with_nframes(self, universe, outfile, Writer): def test_write_contiguous1(self, universe, Writer, outfile): n_atoms = universe.atoms.n_atoms n_frames = len(universe.trajectory) - with Writer(outfile, n_atoms=n_atoms, n_frames=n_frames, chunks=False) as W: + with Writer( + outfile, n_atoms=n_atoms, n_frames=n_frames, chunks=False + ) as W: for ts in universe.trajectory: W.write(universe) @@ -902,8 +951,12 @@ def test_write_contiguous2(self, universe, Writer, outfile): ): assert_equal(dset.chunks, None) - @pytest.mark.parametrize("filter, opts", (("gzip", 1), ("gzip", 9), ("lzf", None))) - def test_write_with_compression(self, universe, outfile, Writer, filter, opts): + @pytest.mark.parametrize( + "filter, opts", (("gzip", 1), ("gzip", 9), ("lzf", None)) + ) + def test_write_with_compression( + self, universe, outfile, Writer, filter, opts + ): with Writer( outfile, universe.atoms.n_atoms, @@ -918,7 +971,9 @@ def test_write_with_compression(self, universe, outfile, Writer, filter, opts): assert_equal(dset.compression, filter) assert_equal(dset.compression_opts, opts) - @pytest.mark.xfail(os.name == "nt", reason="occasional PermissionError on windows") + @pytest.mark.xfail( + os.name == "nt", reason="occasional PermissionError on windows" + ) @pytest.mark.parametrize("driver", ("core", "stdio")) def test_write_with_drivers(self, universe, outfile, Writer, driver): with Writer(outfile, universe.atoms.n_atoms, driver=driver) as W: @@ -955,7 +1010,9 @@ def test_timestep_not_modified_by_writer(self, universe, Writer, outfile): x, err_msg="Positions in Timestep were modified by writer.", ) - assert_equal(ts.time, time, err_msg="Time in Timestep was modified by writer.") + assert_equal( + ts.time, time, err_msg="Time in Timestep was modified by writer." + ) class TestH5PYNotInstalled(object): @@ -981,7 +1038,9 @@ def test_reader_no_h5py(self): def test_writer_no_h5py(self, Writer, outfile): u = mda.Universe(TPR_xvf, TRR_xvf) - with pytest.raises(RuntimeError, match="H5MDWriter: Please install h5py"): + with pytest.raises( + RuntimeError, match="H5MDWriter: Please install h5py" + ): with Writer(outfile, u.atoms.n_atoms) as W: for ts in u.trajectory: W.write(universe) diff --git a/testsuite/MDAnalysisTests/coordinates/test_lammps.py b/testsuite/MDAnalysisTests/coordinates/test_lammps.py index c20f39ecf9..3b203f5bae 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_lammps.py +++ b/testsuite/MDAnalysisTests/coordinates/test_lammps.py @@ -222,14 +222,18 @@ def test_Writer_atoms_types(self, LAMMPSDATAWriter): err_msg="attributes different after writing", ) - @pytest.mark.parametrize("attr", ["bonds", "angles", "dihedrals", "impropers"]) + @pytest.mark.parametrize( + "attr", ["bonds", "angles", "dihedrals", "impropers"] + ) def test_Writer_atoms(self, attr, LAMMPSDATAWriter): u_ref, u_new = LAMMPSDATAWriter ref = getattr(u_ref.atoms, attr) new = getattr(u_new.atoms, attr) assert ref == new, "attributes different after writing" - @pytest.mark.parametrize("attr", ["masses", "charges", "velocities", "positions"]) + @pytest.mark.parametrize( + "attr", ["masses", "charges", "velocities", "positions"] + ) def test_Writer_numerical_attrs(self, attr, LAMMPSDATAWriter): u_ref, u_new = LAMMPSDATAWriter try: @@ -256,7 +260,9 @@ def test_molecule_tag(self, LAMMPSDATAWriter_molecule_tag): ) -@pytest.mark.parametrize("filename", ["out.data", "out.data.bz2", "out.data.gz"]) +@pytest.mark.parametrize( + "filename", ["out.data", "out.data.bz2", "out.data.gz"] +) def test_datawriter_universe(filename, tmpdir): """ Test roundtrip on datawriter, and also checks compressed files @@ -294,7 +300,9 @@ def LAMMPSDATA_partial(tmpdir): return u, u_new - @pytest.mark.parametrize("attr", ["masses", "charges", "velocities", "positions"]) + @pytest.mark.parametrize( + "attr", ["masses", "charges", "velocities", "positions"] + ) def test_Writer_atoms(self, attr, LAMMPSDATA_partial): u_ref, u_new = LAMMPSDATA_partial if hasattr(u_ref.atoms, attr): @@ -342,7 +350,9 @@ def test_n_frames(self, u): assert_equal(u.trajectory.n_frames, self.n_frames) def test_dimensions(self, u): - mean_dimensions = np.mean([ts.dimensions.copy() for ts in u.trajectory], axis=0) + mean_dimensions = np.mean( + [ts.dimensions.copy() for ts in u.trajectory], axis=0 + ) assert_allclose(mean_dimensions, self.mean_dimensions) def test_dt(self, u): @@ -357,11 +367,15 @@ def test_Timestep_time(self, u): assert_allclose( u.trajectory[iframe].time, iframe * self.dt, - err_msg="Time for frame {0} (dt={1}) is wrong.".format(iframe, self.dt), + err_msg="Time for frame {0} (dt={1}) is wrong.".format( + iframe, self.dt + ), ) def test_LAMMPSDCDReader_set_dt(self, u, dt=1500.0): - u = mda.Universe(self.topology, self.trajectory, format=self.format, dt=dt) + u = mda.Universe( + self.topology, self.trajectory, format=self.format, dt=dt + ) iframe = self.get_frame_from_end(1, u) assert_allclose( u.trajectory[iframe].time, @@ -405,14 +419,18 @@ def u(self): def test_Writer_is_LAMMPS(self, u, tmpdir): ext = os.path.splitext(self.trajectory)[1] outfile = str(tmpdir.join("lammps-writer-test" + ext)) - with mda.Writer(outfile, n_atoms=u.atoms.n_atoms, format=self.format) as W: + with mda.Writer( + outfile, n_atoms=u.atoms.n_atoms, format=self.format + ) as W: assert W.flavor, self.flavor def test_Writer(self, u, tmpdir, n_frames=3): ext = os.path.splitext(self.trajectory)[1] outfile = str(tmpdir.join("lammps-writer-test" + ext)) - with mda.Writer(outfile, n_atoms=u.atoms.n_atoms, format=self.format) as w: + with mda.Writer( + outfile, n_atoms=u.atoms.n_atoms, format=self.format + ) as w: for ts in u.trajectory[:n_frames]: w.write(u) @@ -488,7 +506,9 @@ def test_open(self, tmpdir): def test_wrong_time_unit(self, tmpdir): outfile = str(tmpdir.join("lammps-writer-test.dcd")) with pytest.raises(TypeError): - with mda.coordinates.LAMMPS.DCDWriter(outfile, n_atoms=10, timeunit="nm"): + with mda.coordinates.LAMMPS.DCDWriter( + outfile, n_atoms=10, timeunit="nm" + ): pass def test_wrong_unit(self, tmpdir): @@ -563,7 +583,9 @@ def u(self, tmpdir, request): with gzip.GzipFile(f, "wb") as fout: fout.write(data) - yield mda.Universe(f, format="LAMMPSDUMP", lammps_coordinate_convention="auto") + yield mda.Universe( + f, format="LAMMPSDUMP", lammps_coordinate_convention="auto" + ) @pytest.fixture() def u_additional_columns_true(self): @@ -681,9 +703,15 @@ def test_seeking(self, u, reference_positions): u.trajectory[1] assert_allclose(u.dimensions, reference_positions["box"][1], atol=1e-5) - pos = reference_positions["atom1_pos"][1] - reference_positions["mins"][1] + pos = ( + reference_positions["atom1_pos"][1] + - reference_positions["mins"][1] + ) assert_allclose(u.atoms[0].position, pos, atol=1e-5) - pos = reference_positions["atom13_pos"][1] - reference_positions["mins"][1] + pos = ( + reference_positions["atom13_pos"][1] + - reference_positions["mins"][1] + ) assert_allclose(u.atoms[12].position, pos, atol=1e-5) def test_boxsize(self, u, reference_positions): @@ -714,7 +742,9 @@ def test_additional_columns(self, system, fields, request): u = request.getfixturevalue(system) for field in fields: data = u.trajectory[0].data[field] - assert_allclose(data, getattr(RefLAMMPSDataAdditionalColumns, field)) + assert_allclose( + data, getattr(RefLAMMPSDataAdditionalColumns, field) + ) @pytest.mark.parametrize( "system", @@ -723,7 +753,9 @@ def test_additional_columns(self, system, fields, request): ], ) def test_wrong_format_additional_colums(self, system, request): - with pytest.raises(ValueError, match="Please provide an iterable containing"): + with pytest.raises( + ValueError, match="Please provide an iterable containing" + ): request.getfixturevalue(system) @pytest.mark.parametrize( @@ -737,7 +769,9 @@ def test_warning(self, system, request): request.getfixturevalue(system) -@pytest.mark.parametrize("convention", ["unscaled", "unwrapped", "scaled_unwrapped"]) +@pytest.mark.parametrize( + "convention", ["unscaled", "unwrapped", "scaled_unwrapped"] +) def test_open_absent_convention_fails(convention): with pytest.raises(ValueError, match="No coordinates following"): mda.Universe( @@ -749,7 +783,9 @@ def test_open_absent_convention_fails(convention): def test_open_incorrect_convention_fails(): with pytest.raises(ValueError, match="is not a valid option"): - mda.Universe(LAMMPSDUMP, format="LAMMPSDUMP", lammps_coordinate_convention="42") + mda.Universe( + LAMMPSDUMP, format="LAMMPSDUMP", lammps_coordinate_convention="42" + ) @pytest.mark.parametrize( @@ -851,7 +887,9 @@ def reference_unwrapped_positions(self): ] ) - def test_unwrapped_scaled_reference(self, universes, reference_unwrapped_positions): + def test_unwrapped_scaled_reference( + self, universes, reference_unwrapped_positions + ): atom_340 = universes["unwrapped"].atoms[339] for i, ts_u in enumerate(universes["unwrapped"].trajectory[0:3]): assert_allclose( @@ -860,10 +898,14 @@ def test_unwrapped_scaled_reference(self, universes, reference_unwrapped_positio atol=1e-5, ) - def test_unwrapped_scaled_reference(self, universes, reference_unwrapped_positions): + def test_unwrapped_scaled_reference( + self, universes, reference_unwrapped_positions + ): # NOTE use of unscaled positions here due to S->R transform atom_340 = universes["scaled_unwrapped"].atoms[339] - for i, ts_u in enumerate(universes["scaled_unwrapped"].trajectory[0:3]): + for i, ts_u in enumerate( + universes["scaled_unwrapped"].trajectory[0:3] + ): assert_allclose( atom_340.position, reference_unwrapped_positions[i, :], @@ -943,6 +985,8 @@ def test_box(self, u_dump, u_data, reference_box): assert_allclose(ts.dimensions, reference_box, rtol=1e-5, atol=0) for ts in u_dump.trajectory: - assert_allclose(ts.dimensions, u_data.dimensions, rtol=1e-5, atol=0) + assert_allclose( + ts.dimensions, u_data.dimensions, rtol=1e-5, atol=0 + ) assert_allclose(u_data.dimensions, reference_box, rtol=1e-5, atol=0) diff --git a/testsuite/MDAnalysisTests/coordinates/test_memory.py b/testsuite/MDAnalysisTests/coordinates/test_memory.py index 27c7e09216..5d020d43d2 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_memory.py +++ b/testsuite/MDAnalysisTests/coordinates/test_memory.py @@ -73,7 +73,9 @@ def __init__(self): self.jump_to_frame.time = self.jump_to_frame.frame * self.dt def reader(self, trajectory): - return mda.Universe(self.topology, trajectory, in_memory=True).trajectory + return mda.Universe( + self.topology, trajectory, in_memory=True + ).trajectory def iter_ts(self, i): ts = self.universe.trajectory[i] @@ -98,7 +100,9 @@ def test_filename_array(self): # filename attribute of MemoryReader should be None when generated from an array universe = mda.Universe(PSF, DCD) coordinates = universe.trajectory.timeseries(universe.atoms) - universe2 = mda.Universe(PSF, coordinates, format=MemoryReader, order="afc") + universe2 = mda.Universe( + PSF, coordinates, format=MemoryReader, order="afc" + ) assert universe2.trajectory.filename is None def test_default_memory_layout(self): @@ -137,7 +141,9 @@ def test_extract_array_caf(self, reader): assert_equal(reader.timeseries(order="caf").shape, (3, 3341, 98)) def test_timeseries_skip1(self, ref, reader): - assert_equal(reader.timeseries(ref.universe.atoms).shape, (3341, 98, 3)) + assert_equal( + reader.timeseries(ref.universe.atoms).shape, (3341, 98, 3) + ) def test_timeseries_skip10(self, reader): # Check that timeseries skip works similar to numpy slicing @@ -168,7 +174,9 @@ def test_timeseries_view_from_select_all(self, ref, reader): # timeseries() is expected to provide a view of the underlying array # also in the special case when using "all" in selections. selection = ref.universe.select_atoms("all") - assert_equal(reader.timeseries(asel=selection).base is reader.get_array(), True) + assert_equal( + reader.timeseries(asel=selection).base is reader.get_array(), True + ) def test_timeseries_noview(self, ref, reader): # timeseries() is expected NOT to provide a view of the underlying array @@ -192,8 +200,12 @@ def test_float32(self, ref): coordinates = np.random.uniform( size=(100, ref.universe.atoms.n_atoms, 3) ).cumsum(0) - universe = mda.Universe(ref.universe.filename, coordinates, format=MemoryReader) - assert_equal(universe.trajectory.get_array().dtype, np.dtype("float32")) + universe = mda.Universe( + ref.universe.filename, coordinates, format=MemoryReader + ) + assert_equal( + universe.trajectory.get_array().dtype, np.dtype("float32") + ) def test_position_assignation(self, reader): # When coordinates are assigned to a timestep, is the change persistent? diff --git a/testsuite/MDAnalysisTests/coordinates/test_mol2.py b/testsuite/MDAnalysisTests/coordinates/test_mol2.py index cc6761fd48..494b2ace2a 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_mol2.py +++ b/testsuite/MDAnalysisTests/coordinates/test_mol2.py @@ -55,7 +55,9 @@ def test_read(self): assert_equal(u.trajectory.n_frames, 200) u.trajectory[199] - assert_array_almost_equal(u.atoms.positions[0], [1.7240, 11.2730, 14.1200]) + assert_array_almost_equal( + u.atoms.positions[0], [1.7240, 11.2730, 14.1200] + ) def test_read_statusbit(self): u = Universe(mol2_ligand) @@ -111,7 +113,9 @@ def test_comments_header(self): assert_equal(len(u.atoms), 9) assert_equal(u.trajectory.n_frames, 2) u.trajectory[1] - assert_array_almost_equal(u.atoms.positions[2], [-12.2710, -1.9540, -16.0480]) + assert_array_almost_equal( + u.atoms.positions[2], [-12.2710, -1.9540, -16.0480] + ) def test_no_bonds(self, tmpdir): # Issue #3057 @@ -159,7 +163,9 @@ def test_slice_traj(self): def test_reverse_traj(self): frames = [ts.frame for ts in self.traj[20:5:-1]] - assert_equal(frames, list(range(20, 5, -1)), "reversing traj [20:5:-1]") + assert_equal( + frames, list(range(20, 5, -1)), "reversing traj [20:5:-1]" + ) def test_n_frames(self): assert_equal( diff --git a/testsuite/MDAnalysisTests/coordinates/test_netcdf.py b/testsuite/MDAnalysisTests/coordinates/test_netcdf.py index 0f84a386e6..1ebad11665 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_netcdf.py +++ b/testsuite/MDAnalysisTests/coordinates/test_netcdf.py @@ -79,7 +79,9 @@ def test_get_writer(self, universe): assert w.remarks.startswith("AMBER NetCDF format") def test_get_writer_custom_n_atoms(self, universe): - with universe.trajectory.Writer("out.ncdf", n_atoms=42, remarks="Hi!") as w: + with universe.trajectory.Writer( + "out.ncdf", n_atoms=42, remarks="Hi!" + ) as w: assert w.n_atoms == 42 assert w.remarks == "Hi!" @@ -339,7 +341,9 @@ def test_velocities(self, universe, index, expected): @pytest.mark.parametrize("index,expected", ((0, 1.0), (8, 9.0))) def test_time(self, universe, index, expected): - assert_almost_equal(expected, universe.trajectory[index].time, self.prec) + assert_almost_equal( + expected, universe.trajectory[index].time, self.prec + ) def test_nframes(self, universe): assert_equal(10, universe.trajectory.n_frames) @@ -423,12 +427,16 @@ def create_ncdf(self, params): time = ncdf.createVariable("time", "d", ("time",)) setattr(time, "units", params["time"]) time[:] = 1.0 - cell_spatial = ncdf.createVariable("cell_spatial", "c", ("cell_spatial",)) + cell_spatial = ncdf.createVariable( + "cell_spatial", "c", ("cell_spatial",) + ) cell_spatial[:] = np.asarray(list("abc")) cell_angular = ncdf.createVariable( "cell_angular", "c", ("cell_angular", "label") ) - cell_angular[:] = np.asarray([list("alpha"), list("beta "), list("gamma")]) + cell_angular[:] = np.asarray( + [list("alpha"), list("beta "), list("gamma")] + ) # Spatial or atom dependent variables if (params["spatial"]) and (params["n_atoms"]): @@ -465,7 +473,9 @@ def create_ncdf(self, params): velocs = ncdf.createVariable( "velocities", "f8", ("atom", "spatial") ) - forces = ncdf.createVariable("forces", "f8", ("atom", "spatial")) + forces = ncdf.createVariable( + "forces", "f8", ("atom", "spatial") + ) # Set units if params["coordinates"]: @@ -499,10 +509,18 @@ def create_ncdf(self, params): coords[:] = np.asarray( range(params["spatial"]), dtype=np.float32 ) - cell_lengths[:] = np.array([20.0, 20.0, 20.0], dtype=np.float32) - cell_angles[:] = np.array([90.0, 90.0, 90.0], dtype=np.float32) - velocs[:] = np.asarray(range(params["spatial"]), dtype=np.float32) - forces[:] = np.asarray(range(params["spatial"]), dtype=np.float32) + cell_lengths[:] = np.array( + [20.0, 20.0, 20.0], dtype=np.float32 + ) + cell_angles[:] = np.array( + [90.0, 90.0, 90.0], dtype=np.float32 + ) + velocs[:] = np.asarray( + range(params["spatial"]), dtype=np.float32 + ) + forces[:] = np.asarray( + range(params["spatial"]), dtype=np.float32 + ) # self.scale_factor overrides which variable gets a scale_factor if params["scale_factor"]: @@ -692,11 +710,14 @@ def test_conventionversion_warn(self, tmpdir): assert len(record) == 1 wmsg = ( - "NCDF trajectory format is 2.0 but the reader " "implements format 1.0" + "NCDF trajectory format is 2.0 but the reader " + "implements format 1.0" ) assert str(record[0].message.args[0]) == wmsg - @pytest.mark.parametrize("mutation", [{"program": None}, {"programVersion": None}]) + @pytest.mark.parametrize( + "mutation", [{"program": None}, {"programVersion": None}] + ) def test_program_warn(self, tmpdir, mutation): params = self.gen_params(keypair=mutation, restart=False) with tmpdir.as_cwd(): @@ -770,12 +791,14 @@ def _test_write_trajectory(self, universe, outfile): assert_equal( coords[:].dtype.name, np.dtype(np.float32).name, - err_msg="ncdf coord output not float32 " "but {}".format(coords[:].dtype), + err_msg="ncdf coord output not float32 " + "but {}".format(coords[:].dtype), ) assert_equal( time[:].dtype.name, np.dtype(np.float32).name, - err_msg="ncdf time output not float32 " "but {}".format(time[:].dtype), + err_msg="ncdf time output not float32 " + "but {}".format(time[:].dtype), ) def test_write_trajectory_netCDF4(self, universe, outfile): @@ -819,14 +842,16 @@ def _check_new_traj(self, universe, outfile): self.prec, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" + % (orig_ts.frame, written_ts.frame), ) # not a good test because in the example trajectory all times are 0 assert_almost_equal( orig_ts.time, written_ts.time, self.prec, - err_msg="Time for step {0} are not the " "same.".format(orig_ts.frame), + err_msg="Time for step {0} are not the " + "same.".format(orig_ts.frame), ) assert_almost_equal( written_ts.dimensions, @@ -867,13 +892,15 @@ def _check_new_traj(self, universe, outfile): v[:], v_new[:], self.prec, - err_msg="Variable '{0}' not " "written correctly".format(k), + err_msg="Variable '{0}' not " + "written correctly".format(k), ) except TypeError: assert_equal( v[:], v_new[:], - err_msg="Variable {0} not written " "correctly".format(k), + err_msg="Variable {0} not written " + "correctly".format(k), ) def test_TRR2NCDF(self, outfile): @@ -911,7 +938,8 @@ def test_TRR2NCDF(self, outfile): orig_ts.time, written_ts.time, self.prec, - err_msg="Time for step {0} are not the " "same.".format(orig_ts.frame), + err_msg="Time for step {0} are not the " + "same.".format(orig_ts.frame), ) assert_almost_equal( written_ts.dimensions, @@ -939,13 +967,15 @@ def test_write_AtomGroup(self, universe, outfile, outtop): self.prec, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" + % (orig_ts.frame, written_ts.frame), ) assert_almost_equal( orig_ts.time, written_ts.time, self.prec, - err_msg="Time for step {0} are not the " "same.".format(orig_ts.frame), + err_msg="Time for step {0} are not the " + "same.".format(orig_ts.frame), ) assert_almost_equal( written_ts.dimensions, @@ -1027,14 +1057,18 @@ def test_write_u(self, pos, vel, force, tmpdir, u1, u2): u = mda.Universe(self.top, outfile) # check the trajectory contents match reference universes - for ts, ref_ts in zip(u.trajectory, [u1.trajectory.ts, u2.trajectory.ts]): + for ts, ref_ts in zip( + u.trajectory, [u1.trajectory.ts, u2.trajectory.ts] + ): if pos: assert_almost_equal(ts._pos, ref_ts._pos, self.prec) else: with pytest.raises(mda.NoDataError): getattr(ts, "positions") if vel: - assert_almost_equal(ts._velocities, ref_ts._velocities, self.prec) + assert_almost_equal( + ts._velocities, ref_ts._velocities, self.prec + ) else: with pytest.raises(mda.NoDataError): getattr(ts, "velocities") @@ -1195,11 +1229,15 @@ def test_write_read_write( for ts1, ts3 in zip(universe.trajectory, universe3.trajectory): assert_almost_equal(ts1.time, ts3.time) assert_almost_equal(ts1.dimensions, ts3.dimensions) - assert_almost_equal(universe.atoms.positions, universe3.atoms.positions, 4) + assert_almost_equal( + universe.atoms.positions, universe3.atoms.positions, 4 + ) assert_almost_equal( universe.atoms.velocities, universe3.atoms.velocities, 4 ) - assert_almost_equal(universe.atoms.forces, universe3.atoms.forces, 4) + assert_almost_equal( + universe.atoms.forces, universe3.atoms.forces, 4 + ) class TestScipyScaleFactors(TestNCDFWriterScaleFactors): @@ -1208,7 +1246,9 @@ class TestScipyScaleFactors(TestNCDFWriterScaleFactors): @pytest.fixture(autouse=True) def block_netcdf4(self, monkeypatch): - monkeypatch.setattr(sys.modules["MDAnalysis.coordinates.TRJ"], "netCDF4", None) + monkeypatch.setattr( + sys.modules["MDAnalysis.coordinates.TRJ"], "netCDF4", None + ) def test_ncdf4_not_present(self, outfile, universe): # whilst we're here, let's also test this warning diff --git a/testsuite/MDAnalysisTests/coordinates/test_pdb.py b/testsuite/MDAnalysisTests/coordinates/test_pdb.py index 9ef3c52d3c..9c88b97ffd 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_pdb.py +++ b/testsuite/MDAnalysisTests/coordinates/test_pdb.py @@ -64,7 +64,9 @@ assert_allclose, ) -IGNORE_NO_INFORMATION_WARNING = "ignore:Found no information for attr:UserWarning" +IGNORE_NO_INFORMATION_WARNING = ( + "ignore:Found no information for attr:UserWarning" +) @pytest.fixture @@ -114,7 +116,8 @@ def test_ENT(self): class TestPDBMetadata(object): header = "HYDROLASE 11-MAR-12 4E43" title = [ - "HIV PROTEASE (PR) DIMER WITH ACETATE IN EXO SITE AND PEPTIDE " "IN ACTIVE", + "HIV PROTEASE (PR) DIMER WITH ACETATE IN EXO SITE AND PEPTIDE " + "IN ACTIVE", "2 SITE", ] compnd = [ @@ -162,7 +165,9 @@ def test_TITLE(self, universe): len(self.title), err_msg="TITLE does not contain same number of lines", ) - for lineno, (parsed, reference) in enumerate(zip(title, self.title), start=1): + for lineno, (parsed, reference) in enumerate( + zip(title, self.title), start=1 + ): assert_equal( parsed, reference, @@ -173,7 +178,9 @@ def test_COMPND(self, universe): try: compound = universe.trajectory.compound except AttributeError: - raise AssertionError("Reader does not have a 'compound' attribute.") + raise AssertionError( + "Reader does not have a 'compound' attribute." + ) assert_equal( len(compound), len(self.compnd), @@ -200,7 +207,9 @@ def test_REMARK(self, universe): ) # only look at the first 5 entries for lineno, (parsed, reference) in enumerate( - zip(remarks[: self.nmax_remarks], self.remarks[: self.nmax_remarks]), + zip( + remarks[: self.nmax_remarks], self.remarks[: self.nmax_remarks] + ), start=1, ): assert_equal( @@ -214,7 +223,9 @@ class TestExtendedPDBReader(_SingleFrameReader): __test__ = True def setUp(self): - self.universe = mda.Universe(PDB_small, topology_format="XPDB", format="XPDB") + self.universe = mda.Universe( + PDB_small, topology_format="XPDB", format="XPDB" + ) # 3 decimals in PDB spec # http://www.wwpdb.org/documentation/format32/sect9.html#ATOM self.prec = 3 @@ -266,7 +277,9 @@ def universe_and_expected_dims(self, request): @pytest.fixture def outfile(self, tmpdir): - return str(tmpdir.mkdir("PDBWriter").join("primitive-pdb-writer" + self.ext)) + return str( + tmpdir.mkdir("PDBWriter").join("primitive-pdb-writer" + self.ext) + ) @pytest.fixture def u_no_ids(self): @@ -285,7 +298,9 @@ def u_no_ids(self): trajectory=True, ) universe.add_TopologyAttr("icodes", [" "] * len(universe.residues)) - universe.add_TopologyAttr("record_types", ["ATOM"] * len(universe.atoms)) + universe.add_TopologyAttr( + "record_types", ["ATOM"] * len(universe.atoms) + ) universe.dimensions = [10, 10, 10, 90, 90, 90] return universe @@ -392,7 +407,8 @@ def test_write_single_frame_AtomGroup(self, universe2, outfile): u.atoms.positions, self.prec, err_msg="Written coordinates do not " - "agree with original coordinates from frame %d" % u.trajectory.frame, + "agree with original coordinates from frame %d" + % u.trajectory.frame, ) def test_write_nodims(self, universe_and_expected_dims, outfile): @@ -412,9 +428,7 @@ def test_write_nodims(self, universe_and_expected_dims, outfile): else: assert np.allclose(u.dimensions, expected_dims) - expected_msg = ( - "Unit cell dimensions not found. CRYST1 record set to unitary values." - ) + expected_msg = "Unit cell dimensions not found. CRYST1 record set to unitary values." with pytest.warns(UserWarning, match=expected_msg): u.atoms.write(outfile) @@ -437,7 +451,8 @@ def test_write_nodims(self, universe_and_expected_dims, outfile): uout.atoms.positions, self.prec, err_msg="Written coordinates do not " - "agree with original coordinates from frame %d" % u.trajectory.frame, + "agree with original coordinates from frame %d" + % u.trajectory.frame, ) def test_check_coordinate_limits_min(self, universe, outfile): @@ -480,7 +495,9 @@ def test_check_HEADER_TITLE_multiframe(self, universe2, outfile): assert got_title <= 1, "There should be only one TITLE." @pytest.mark.parametrize("startframe,maxframes", [(0, 12), (9997, 12)]) - def test_check_MODEL_multiframe(self, universe2, outfile, startframe, maxframes): + def test_check_MODEL_multiframe( + self, universe2, outfile, startframe, maxframes + ): """Check whether MODEL number is in the right column (Issue #1950)""" u = universe2 protein = u.select_atoms("protein and name CA") @@ -550,12 +567,18 @@ def test_hetatm_written(self, universe4, tmpdir, outfile): u.atoms.write(outfile) written = mda.Universe(outfile) - written_atoms = written.select_atoms("resname ETA and " "record_type HETATM") + written_atoms = written.select_atoms( + "resname ETA and " "record_type HETATM" + ) assert len(u_hetatms) == len(written_atoms), "mismatched HETATM number" - assert_almost_equal(u_hetatms.atoms.positions, written_atoms.atoms.positions) + assert_almost_equal( + u_hetatms.atoms.positions, written_atoms.atoms.positions + ) - def test_default_atom_record_type_written(self, universe5, tmpdir, outfile): + def test_default_atom_record_type_written( + self, universe5, tmpdir, outfile + ): """ Checks that ATOM record types are written when there is no record_type attribute. @@ -1002,7 +1025,9 @@ def universe(): def test_load_pdb(self, universe): U = universe - assert_equal(len(U.atoms), self.ref_n_atoms, "load Universe from big PDB") + assert_equal( + len(U.atoms), self.ref_n_atoms, "load Universe from big PDB" + ) assert_equal( U.atoms.select_atoms("resid 150 and name HA2").atoms[0], U.atoms[self.ref_E151HA2_index], @@ -1298,9 +1323,9 @@ def test_deduce_PDB_atom_name(atom, refname): # The Pair named tuple is used to mock atoms as we only need them to have a # ``resname`` and a ``name`` attribute. dummy_file = StringIO() - name = mda.coordinates.PDB.PDBWriter(dummy_file, n_atoms=1)._deduce_PDB_atom_name( - atom.name, atom.resname - ) + name = mda.coordinates.PDB.PDBWriter( + dummy_file, n_atoms=1 + )._deduce_PDB_atom_name(atom.name, atom.resname) assert_equal(name, refname) @@ -1340,7 +1365,9 @@ def test_len(self, pdbfile): def test_order(self, pdbfile): u = mda.Universe(pdbfile) - for ts, refbox, refpos in zip(u.trajectory, self.boxsize, self.position): + for ts, refbox, refpos in zip( + u.trajectory, self.boxsize, self.position + ): assert_almost_equal(u.dimensions[0], refbox) assert_almost_equal(u.atoms[0].position[0], refpos) @@ -1384,7 +1411,9 @@ def test_write_pdb_zero_atoms(tmpdir): def test_atom_not_match(tmpdir): # issue 1998 - outfile = str(tmpdir.mkdir("PDBReader").join("test_atom_not_match" + ".pdb")) + outfile = str( + tmpdir.mkdir("PDBReader").join("test_atom_not_match" + ".pdb") + ) u = mda.Universe(PSF, DCD) # select two groups of atoms protein = u.select_atoms("protein and name CA") @@ -1408,7 +1437,11 @@ def test_partially_missing_cryst(): # mangle the cryst lines so that only box angles are left # this mimics '6edu' from PDB raw = [ - (line if not line.startswith("CRYST") else line[:6] + " " * 28 + line[34:]) + ( + line + if not line.startswith("CRYST") + else line[:6] + " " * 28 + line[34:] + ) for line in raw ] @@ -1430,7 +1463,9 @@ def test_write_no_atoms_elements(dummy_universe_without_elements): writer.write(dummy_universe_without_elements.atoms) content = destination.getvalue() element_symbols = [ - line[76:78].strip() for line in content.splitlines() if line[:6] == "ATOM " + line[76:78].strip() + for line in content.splitlines() + if line[:6] == "ATOM " ] expectation = ["", "", "", "", ""] assert element_symbols == expectation @@ -1452,7 +1487,9 @@ def test_write_atom_elements(dummy_universe_without_elements): writer.write(dummy_universe_without_elements.atoms) content = destination.getvalue() element_symbols = [ - line[76:78].strip() for line in content.splitlines() if line[:6] == "ATOM " + line[76:78].strip() + for line in content.splitlines() + if line[:6] == "ATOM " ] assert element_symbols == expectation @@ -1476,7 +1513,9 @@ def test_elements_roundtrip(tmpdir): def test_cryst_meaningless_warning(): # issue 2599 # FIXME: This message might change with Issue #2698 - with pytest.warns(UserWarning, match="Unit cell dimensions will be set to None."): + with pytest.warns( + UserWarning, match="Unit cell dimensions will be set to None." + ): mda.Universe(PDB_CRYOEM_BOX) @@ -1549,7 +1588,9 @@ def test_read_segids(): ATOM 665 OG1 THR A 315 21.047 13.922 1.304 1.00 15.14 B O """ - u_invalid_segid = mda.Universe(StringIO(invalid_seg_format_str), format="PDB") + u_invalid_segid = mda.Universe( + StringIO(invalid_seg_format_str), format="PDB" + ) u_acceptable = mda.Universe(StringIO(acceptable_format_str), format="PDB") u_standard = mda.Universe(StringIO(standard_format_str), format="PDB") @@ -1557,7 +1598,9 @@ def test_read_segids(): # Thus, segids existed and were set to "B" for all atoms. # After version 2.10.0, segid is read from column 73-76. # segid is expected to set by chainID "A" for all atoms. - assert_equal(u_invalid_segid.atoms.segids, ["A"] * len(u_invalid_segid.atoms)) + assert_equal( + u_invalid_segid.atoms.segids, ["A"] * len(u_invalid_segid.atoms) + ) # Before version 2.10.0, segid was set to read from column 67-76. # Due to misalignment in b-factor column, diff --git a/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py b/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py index c358f77570..06bc62830b 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py +++ b/testsuite/MDAnalysisTests/coordinates/test_pdbqt.py @@ -79,7 +79,9 @@ def test_neighborhood(self, universe): assert_equal(len(residue_neighbors), 80) def test_n_frames(self, universe): - assert_equal(universe.trajectory.n_frames, 1, "wrong number of frames in pdb") + assert_equal( + universe.trajectory.n_frames, 1, "wrong number of frames in pdb" + ) def test_time(self, universe): assert_equal(universe.trajectory.time, 0.0, "wrong time of the frame") diff --git a/testsuite/MDAnalysisTests/coordinates/test_pqr.py b/testsuite/MDAnalysisTests/coordinates/test_pqr.py index 9f6798c5b9..fc69337ddb 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_pqr.py +++ b/testsuite/MDAnalysisTests/coordinates/test_pqr.py @@ -93,7 +93,9 @@ def universe(): prec = 3 - @pytest.mark.parametrize("filename", ["test.pqr", "test.pqr.bz2", "test.pqr.gz"]) + @pytest.mark.parametrize( + "filename", ["test.pqr", "test.pqr.bz2", "test.pqr.gz"] + ) def test_simple_writer_roundtrip(self, universe, filename, tmpdir): with tmpdir.as_cwd(): universe.atoms.write(filename) diff --git a/testsuite/MDAnalysisTests/coordinates/test_reader_api.py b/testsuite/MDAnalysisTests/coordinates/test_reader_api.py index 9094e22588..4ae5c0f5c6 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_reader_api.py +++ b/testsuite/MDAnalysisTests/coordinates/test_reader_api.py @@ -103,7 +103,9 @@ def test_required_attributes(self, reader): "units", "format", ]: - assert_equal(hasattr(reader, attr), True, "Missing attr: {0}".format(attr)) + assert_equal( + hasattr(reader, attr), True, "Missing attr: {0}".format(attr) + ) def test_iter(self, reader): l = [ts for ts in reader] diff --git a/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py b/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py index 781d4866aa..1b2bc468b3 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py +++ b/testsuite/MDAnalysisTests/coordinates/test_timestep_api.py @@ -175,7 +175,9 @@ def test_volume(self, ts): assert_equal(ts.volume, self.ref_volume) def test_triclinic_vectors(self, ts): - assert_allclose(ts.triclinic_dimensions, triclinic_vectors(ts.dimensions)) + assert_allclose( + ts.triclinic_dimensions, triclinic_vectors(ts.dimensions) + ) def test_set_triclinic_vectors(self, ts): ref_vec = triclinic_vectors(self.newbox) @@ -404,7 +406,9 @@ def _check_copy(self, name, ref_ts): """Check basic copy""" ts2 = ref_ts.copy() - err_msg = "Timestep copy failed for format {form}" " on attribute {att}" + err_msg = ( + "Timestep copy failed for format {form}" " on attribute {att}" + ) # eq method checks: # - frame @@ -413,7 +417,9 @@ def _check_copy(self, name, ref_ts): assert ref_ts == ts2 if not ref_ts.dimensions is None: - assert_array_almost_equal(ref_ts.dimensions, ts2.dimensions, decimal=4) + assert_array_almost_equal( + ref_ts.dimensions, ts2.dimensions, decimal=4 + ) else: assert ref_ts.dimensions == ts2.dimensions @@ -505,7 +511,9 @@ def test_copy(self, func, ts): ts = u.trajectory.ts func(self, self.name, ts) - @pytest.fixture(params=filter(any, itertools.product([True, False], repeat=3))) + @pytest.fixture( + params=filter(any, itertools.product([True, False], repeat=3)) + ) def some_ts(self, request): p, v, f = request.param return self._from_coords(p, v, f) @@ -711,7 +719,9 @@ class TestBaseTimestepInterface(object): ) ) def universe(self, request): - topology, trajectory, trajectory_format, topology_format = request.param + topology, trajectory, trajectory_format, topology_format = ( + request.param + ) if trajectory_format is not None and topology_format is not None: return mda.Universe( topology, diff --git a/testsuite/MDAnalysisTests/coordinates/test_tng.py b/testsuite/MDAnalysisTests/coordinates/test_tng.py index 905f612bc4..8eaa64d5ec 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_tng.py +++ b/testsuite/MDAnalysisTests/coordinates/test_tng.py @@ -241,7 +241,9 @@ def test_initial_frame_is_0(self, universe): assert_equal( universe.trajectory.ts.frame, 0, - "initial frame is not 0 but {0}".format(universe.trajectory.ts.frame), + "initial frame is not 0 but {0}".format( + universe.trajectory.ts.frame + ), ) def test_starts_with_first_frame(self, universe): @@ -253,7 +255,9 @@ def test_rewind(self, universe): trj = universe.trajectory trj.next() trj.next() # for readers that do not support indexing - assert_equal(trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)") + assert_equal( + trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)" + ) trj.rewind() assert_equal(trj.ts.frame, 0, "failed to rewind to first frame") assert np.any(universe.atoms.positions > 0) @@ -289,7 +293,9 @@ def test_positions_first_frame(self, universe): def test_box_first_frame(self, universe): dims = universe.trajectory[0].dimensions - assert_allclose(dims, triclinic_box(*self._box_frame_0), rtol=10**-self.prec) + assert_allclose( + dims, triclinic_box(*self._box_frame_0), rtol=10**-self.prec + ) def test_positions_last_frame(self, universe): pos = universe.trajectory[100].positions @@ -301,7 +307,9 @@ def test_positions_last_frame(self, universe): def test_box_last_frame(self, universe): dims = universe.trajectory[100].dimensions - assert_allclose(dims, triclinic_box(*self._box_frame_100), rtol=10**-self.prec) + assert_allclose( + dims, triclinic_box(*self._box_frame_100), rtol=10**-self.prec + ) @pytest.mark.parametrize("frame", [0, 20, 50, 100]) def test_step(self, universe, frame): @@ -313,21 +321,29 @@ def test_lambda_in_ts(self, universe): ts = universe.trajectory[10] assert "TNG_GMX_LAMBDA" in ts.data.keys() assert isinstance(ts.data["TNG_GMX_LAMBDA"], np.ndarray) - assert_equal(ts.data["TNG_GMX_LAMBDA"], np.asarray([[0]], dtype=np.float32)) + assert_equal( + ts.data["TNG_GMX_LAMBDA"], np.asarray([[0]], dtype=np.float32) + ) def test_read_box_fail_strange_step(self, universe): stepnum = 123 # step number with no data iterator_step = universe.trajectory._file_iterator.read_step(stepnum) with pytest.raises(IOError, match="Failed to read box from TNG file"): - universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) + universe.trajectory._frame_to_ts( + iterator_step, universe.trajectory.ts + ) def test_read_pos_fail_strange_step(self, universe): stepnum = 123 # step number with no data iterator_step = universe.trajectory._file_iterator.read_step(stepnum) # set _has_box to False to trigger position reading error universe.trajectory._has_box = False - with pytest.raises(IOError, match="Failed to read positions from TNG file"): - universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) + with pytest.raises( + IOError, match="Failed to read positions from TNG file" + ): + universe.trajectory._frame_to_ts( + iterator_step, universe.trajectory.ts + ) def test_additional_block_read_fails(self, universe): stepnum = 123 # step number with no data @@ -339,7 +355,9 @@ def test_additional_block_read_fails(self, universe): with pytest.raises( IOError, match="Failed to read additional block TNG_GMX_LAMBDA" ): - universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) + universe.trajectory._frame_to_ts( + iterator_step, universe.trajectory.ts + ) def test_parse_n_atoms(self, universe): assert universe.trajectory.parse_n_atoms(TNG_traj) == self._n_atoms @@ -394,8 +412,12 @@ def test_read_vels_fail_strange_step(self, universe): # set _has_* attrs to False to trigger velocities reading error universe.trajectory._has_box = False universe.trajectory._has_positions = False - with pytest.raises(IOError, match="Failed to read velocities from TNG file"): - universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) + with pytest.raises( + IOError, match="Failed to read velocities from TNG file" + ): + universe.trajectory._frame_to_ts( + iterator_step, universe.trajectory.ts + ) def test_read_force_fail_strange_step(self, universe): stepnum = 123 # step number with no data @@ -404,8 +426,12 @@ def test_read_force_fail_strange_step(self, universe): universe.trajectory._has_box = False universe.trajectory._has_positions = False universe.trajectory._has_velocities = False - with pytest.raises(IOError, match="Failed to read forces from TNG file"): - universe.trajectory._frame_to_ts(iterator_step, universe.trajectory.ts) + with pytest.raises( + IOError, match="Failed to read forces from TNG file" + ): + universe.trajectory._frame_to_ts( + iterator_step, universe.trajectory.ts + ) @pytest.mark.skipif(not HAS_PYTNG, reason="pytng not installed") diff --git a/testsuite/MDAnalysisTests/coordinates/test_trc.py b/testsuite/MDAnalysisTests/coordinates/test_trc.py index f9fde47aa3..5069fe3ed3 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_trc.py +++ b/testsuite/MDAnalysisTests/coordinates/test_trc.py @@ -53,7 +53,9 @@ def test_trc_positions(self, TRC_U): ) # fith frame first particle TRC_U.trajectory[4] - assert_allclose(TRC_U.atoms.positions[0], [0.37026654, 22.78805010, 3.69695262]) + assert_allclose( + TRC_U.atoms.positions[0], [0.37026654, 22.78805010, 3.69695262] + ) def test_trc_dimensions(self, TRC_U): assert TRC_U.trajectory[0].dimensions is None @@ -94,9 +96,13 @@ def test_rewind(self, TRC_U): trc.next() trc.next() trc.next() - assert trc.ts.frame == 4, "trajectory.next() did not forward to frameindex 4" + assert ( + trc.ts.frame == 4 + ), "trajectory.next() did not forward to frameindex 4" trc.rewind() - assert trc.ts.frame == 0, "trajectory.rewind() failed to rewind to first frame" + assert ( + trc.ts.frame == 0 + ), "trajectory.rewind() failed to rewind to first frame" assert np.any( TRC_U.atoms.positions != 0 @@ -215,8 +221,14 @@ def test_trc_distances(self, TRC_U): ag1 = atom_1a + atom_1b + atom_1c + atom_1d ag2 = atom_2a + atom_2b + atom_2c + atom_2d - dist_A = distances.dist(ag1, ag2, box=ts.dimensions)[2] # return distance - dist_B = atomicdistances.AtomicDistances(ag1, ag2, pbc=True).run().results[0] + dist_A = distances.dist(ag1, ag2, box=ts.dimensions)[ + 2 + ] # return distance + dist_B = ( + atomicdistances.AtomicDistances(ag1, ag2, pbc=True) + .run() + .results[0] + ) assert_allclose( dist_A, [5.9488481, 4.4777278, 20.8165518, 7.5727112], rtol=1e-06 @@ -234,7 +246,9 @@ def test_universe(self): class TestTRCGenboxOrigin: def test_universe(self): - with pytest.raises(ValueError, match="doesnt't support a shifted origin!"): + with pytest.raises( + ValueError, match="doesnt't support a shifted origin!" + ): mda.Universe(TRC_PDB_VAC, TRC_GENBOX_ORIGIN) @@ -251,7 +265,9 @@ class TestTRCEmptyFile: def test_universe(self): with pytest.raises( ValueError, - match=("No supported blocks were found within the GROMOS trajectory!"), + match=( + "No supported blocks were found within the GROMOS trajectory!" + ), ): mda.Universe(TRC_PDB_VAC, TRC_EMPTY) @@ -290,12 +306,16 @@ def test_trc_n_frames(self, TRC_U): assert TRC_U.trajectory.n_frames == 3 def test_trc_frame(self, TRC_U): - with pytest.warns(UserWarning, match="POSITION block is not supported!"): + with pytest.warns( + UserWarning, match="POSITION block is not supported!" + ): assert TRC_U.trajectory[0].frame == 0 assert TRC_U.trajectory[2].frame == 2 def test_trc_time(self, TRC_U): - with pytest.warns(UserWarning, match="POSITION block is not supported!"): + with pytest.warns( + UserWarning, match="POSITION block is not supported!" + ): assert TRC_U.trajectory[0].time == 0 assert TRC_U.trajectory[2].time == 0 diff --git a/testsuite/MDAnalysisTests/coordinates/test_trj.py b/testsuite/MDAnalysisTests/coordinates/test_trj.py index b6de892335..65c1e62dba 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_trj.py +++ b/testsuite/MDAnalysisTests/coordinates/test_trj.py @@ -69,19 +69,24 @@ def test_amber_proteinselection(self, universe): def test_sum_centres_of_geometry(self, universe): protein = universe.select_atoms("protein") - total = np.sum([protein.center_of_geometry() for ts in universe.trajectory]) + total = np.sum( + [protein.center_of_geometry() for ts in universe.trajectory] + ) assert_almost_equal( total, self.ref_sum_centre_of_geometry, self.prec, - err_msg="sum of centers of geometry over the " "trajectory do not match", + err_msg="sum of centers of geometry over the " + "trajectory do not match", ) def test_initial_frame_is_0(self, universe): assert_equal( universe.trajectory.ts.frame, 0, - "initial frame is not 0 but {0}".format(universe.trajectory.ts.frame), + "initial frame is not 0 but {0}".format( + universe.trajectory.ts.frame + ), ) def test_starts_with_first_frame(self, universe): @@ -95,7 +100,9 @@ def test_rewind(self, universe): trj = universe.trajectory trj.next() trj.next() # for readers that do not support indexing - assert_equal(trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)") + assert_equal( + trj.ts.frame, 2, "failed to forward to frame 2 (frameindex 2)" + ) trj.rewind() assert_equal(trj.ts.frame, 0, "failed to rewind to first frame") assert np.any(universe.atoms.positions > 0), ( diff --git a/testsuite/MDAnalysisTests/coordinates/test_trz.py b/testsuite/MDAnalysisTests/coordinates/test_trz.py index aef058a620..8e42bc644f 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_trz.py +++ b/testsuite/MDAnalysisTests/coordinates/test_trz.py @@ -60,12 +60,16 @@ def universe(self): def test_load_trz(self, universe): U = universe - assert_equal(len(U.atoms), self.ref_n_atoms, "load Universe from PSF and TRZ") + assert_equal( + len(U.atoms), self.ref_n_atoms, "load Universe from PSF and TRZ" + ) def test_next_trz(self, universe): assert_equal(universe.trajectory.ts.frame, 0, "starts at first frame") universe.trajectory.next() - assert_equal(universe.trajectory.ts.frame, 1, "next returns frame index 1") + assert_equal( + universe.trajectory.ts.frame, 1, "next returns frame index 1" + ) def test_rewind_trz(self, universe): # move to different frame and rewind to get first frame back @@ -151,7 +155,9 @@ def test_time(self, universe): ) def test_title(self, universe): - assert_equal(self.ref_title, universe.trajectory.title, "wrong title in trz") + assert_equal( + self.ref_title, universe.trajectory.title, "wrong title in trz" + ) def test_get_writer(self, universe, tmpdir): self.outfile = os.path.join(str(tmpdir), "test-trz-writer.trz") @@ -254,7 +260,9 @@ def test_no_box_warning(self, outfile): u = mda.Universe.empty(10, trajectory=True) u.dimensions = None - with pytest.warns(UserWarning, match="box will be written as all zero values"): + with pytest.warns( + UserWarning, match="box will be written as all zero values" + ): with mda.Writer(outfile, n_atoms=10) as w: w.write(u.atoms) diff --git a/testsuite/MDAnalysisTests/coordinates/test_txyz.py b/testsuite/MDAnalysisTests/coordinates/test_txyz.py index 770af1a8a1..66cd38067e 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_txyz.py +++ b/testsuite/MDAnalysisTests/coordinates/test_txyz.py @@ -44,17 +44,23 @@ def ARC_PBC_U(): def test_txyz_positions(TXYZ_U): - assert_almost_equal(TXYZ_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000]) + assert_almost_equal( + TXYZ_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000] + ) def test_arc_positions(ARC_U): - assert_almost_equal(ARC_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000]) + assert_almost_equal( + ARC_U.atoms.positions[0], [-6.553398, -1.854369, 0.000000] + ) def test_arc_positions_frame_2(ARC_U): ARC_U.trajectory[1] - assert_almost_equal(ARC_U.atoms.positions[0], [-0.231579, -0.350841, -0.037475]) + assert_almost_equal( + ARC_U.atoms.positions[0], [-0.231579, -0.350841, -0.037475] + ) def test_arc_traj_length(ARC_U): diff --git a/testsuite/MDAnalysisTests/coordinates/test_writer_api.py b/testsuite/MDAnalysisTests/coordinates/test_writer_api.py index d7f55a6b89..4c3ac08cb5 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_writer_api.py +++ b/testsuite/MDAnalysisTests/coordinates/test_writer_api.py @@ -28,7 +28,8 @@ # grab all known writers # sort so test order is predictable for parallel tests writers = sorted( - set(mda._MULTIFRAME_WRITERS.values()) | set(mda._SINGLEFRAME_WRITERS.values()), + set(mda._MULTIFRAME_WRITERS.values()) + | set(mda._SINGLEFRAME_WRITERS.values()), key=lambda x: x.__name__, ) known_ts_haters = [ @@ -54,7 +55,8 @@ def test_ts_error(writer, tmpdir): elif writer == mda.coordinates.LAMMPS.DATAWriter: pytest.skip("DATAWriter requires integer atom types") elif ( - writer == mda.coordinates.H5MD.H5MDWriter and not mda.coordinates.H5MD.HAS_H5PY + writer == mda.coordinates.H5MD.H5MDWriter + and not mda.coordinates.H5MD.HAS_H5PY ): pytest.skip("skipping H5MDWriter test because h5py is not installed") else: @@ -87,7 +89,8 @@ def test_write_with_atomgroup(writer, tmpdir): elif writer == mda.coordinates.LAMMPS.DATAWriter: pytest.skip("DATAWriter requires integer atom types") elif ( - writer == mda.coordinates.H5MD.H5MDWriter and not mda.coordinates.H5MD.HAS_H5PY + writer == mda.coordinates.H5MD.H5MDWriter + and not mda.coordinates.H5MD.HAS_H5PY ): pytest.skip("skipping H5MDWriter test because h5py is not installed") else: @@ -115,7 +118,8 @@ def test_write_with_universe(writer, tmpdir): elif writer == mda.coordinates.LAMMPS.DATAWriter: pytest.skip("DATAWriter requires integer atom types") elif ( - writer == mda.coordinates.H5MD.H5MDWriter and not mda.coordinates.H5MD.HAS_H5PY + writer == mda.coordinates.H5MD.H5MDWriter + and not mda.coordinates.H5MD.HAS_H5PY ): pytest.skip("skipping H5MDWriter test because h5py is not installed") else: diff --git a/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py b/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py index 984799bfc2..616bae0ef6 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py +++ b/testsuite/MDAnalysisTests/coordinates/test_writer_registration.py @@ -47,7 +47,9 @@ def test_default_multiframe(self): def test_singleframe(self): # check that singleframe=False has been respected - assert isinstance(mda.Writer("this.magic", multiframe=False), self.MagicWriter) + assert isinstance( + mda.Writer("this.magic", multiframe=False), self.MagicWriter + ) def test_multiframe_magic2(self): # this will work as we go for multiframe diff --git a/testsuite/MDAnalysisTests/coordinates/test_xdr.py b/testsuite/MDAnalysisTests/coordinates/test_xdr.py index a9631f17d2..2a2f236924 100644 --- a/testsuite/MDAnalysisTests/coordinates/test_xdr.py +++ b/testsuite/MDAnalysisTests/coordinates/test_xdr.py @@ -145,7 +145,9 @@ def test_jump_xdrtrj(self, universe): def test_jump_lastframe_xdrtrj(self, universe): universe.trajectory[-1] - assert_equal(universe.coord.frame, 9, "indexing last frame with trajectory[-1]") + assert_equal( + universe.coord.frame, 9, "indexing last frame with trajectory[-1]" + ) def test_slice_xdrtrj(self, universe): frames = [ts.frame for ts in universe.trajectory[2:9:3]] @@ -156,7 +158,9 @@ def test_reverse_xdrtrj(self, universe): assert_equal(frames, list(range(9, -1, -1)), "slicing xdrtrj [::-1]") def test_coordinates(self, universe): - ca_nm = np.array([[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32) + ca_nm = np.array( + [[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32 + ) # coordinates in the base unit (needed for True) ca_Angstrom = ca_nm * 10.0 universe.trajectory.rewind() @@ -271,7 +275,9 @@ def test_Writer(self, tmpdir, dt): assert_equal(u.trajectory.n_frames, 2) # prec = 6: TRR test fails; here I am generous and take self.prec = # 3... - assert_almost_equal(u.atoms.positions, universe.atoms.positions, self.prec) + assert_almost_equal( + u.atoms.positions, universe.atoms.positions, self.prec + ) if dt: # test total trajectory length assert_almost_equal( @@ -279,7 +285,8 @@ def test_Writer(self, tmpdir, dt): dt, 3, err_msg=( - "wrong total length of trajectory upon setting dt " "explicitly" + "wrong total length of trajectory upon setting dt " + "explicitly" ), ) @@ -360,7 +367,8 @@ def test_velocities(self, universe): universe.atoms.velocities[[47675, 47676]], v_base, self.prec, - err_msg="velocities for indices 47675,47676 do not " "match known values", + err_msg="velocities for indices 47675,47676 do not " + "match known values", ) for index, v_known in zip([47675, 47676], v_base): @@ -383,11 +391,15 @@ def universe(self): def test_coordinates(self, universe): # note: these are the native coordinates in nm - ca_nm = np.array([[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32) + ca_nm = np.array( + [[6.043369675, 7.385184479, 1.381425762]], dtype=np.float32 + ) universe.trajectory.rewind() universe.trajectory.next() universe.trajectory.next() - assert_equal(universe.trajectory.ts.frame, 2, "failed to step to frame 3") + assert_equal( + universe.trajectory.ts.frame, 2, "failed to step to frame 3" + ) ca = universe.select_atoms("name CA and resid 122") # low precision match because we also look at the trr: only 3 decimals # in nm in xtc! @@ -432,7 +444,9 @@ def outfile(self, tmpdir): def test_write_trajectory(self, universe, Writer, outfile): """Test writing Gromacs trajectories (Issue 38)""" - with Writer(outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt) as W: + with Writer( + outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt + ) as W: for ts in universe.trajectory: W.write(universe) @@ -446,7 +460,8 @@ def test_write_trajectory(self, universe, Writer, outfile): 3, err_msg="coordinate mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" + % (orig_ts.frame, written_ts.frame), ) def test_timestep_not_modified_by_writer(self, universe, Writer, outfile): @@ -467,7 +482,9 @@ def test_timestep_not_modified_by_writer(self, universe, Writer, outfile): x, err_msg="Positions in Timestep were modified by writer.", ) - assert_equal(ts.time, time, err_msg="Time in Timestep was modified by writer.") + assert_equal( + ts.time, time, err_msg="Time in Timestep was modified by writer." + ) class TestXTCWriter(_GromacsWriter): @@ -480,7 +497,9 @@ class TestTRRWriter(_GromacsWriter): infilename = TRR def test_velocities(self, universe, Writer, outfile): - with Writer(outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt) as W: + with Writer( + outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt + ) as W: for ts in universe.trajectory: W.write(universe) @@ -494,13 +513,16 @@ def test_velocities(self, universe, Writer, outfile): 3, err_msg="velocities mismatch between " "original and written trajectory at " - "frame %d (orig) vs %d (written)" % (orig_ts.frame, written_ts.frame), + "frame %d (orig) vs %d (written)" + % (orig_ts.frame, written_ts.frame), ) def test_gaps(self, universe, Writer, outfile): """Tests the writing and reading back of TRRs with gaps in any of the coordinates/velocities properties.""" - with Writer(outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt) as W: + with Writer( + outfile, universe.atoms.n_atoms, dt=universe.trajectory.dt + ) as W: for ts in universe.trajectory: # Inset some gaps in the properties: coords every 4 steps, vels # every 2. @@ -572,7 +594,9 @@ def test_data_preservation(self, universe, Writer, outfile): # check that each value is the same for k in orig_ts.data: - assert_allclose(orig_ts.data[k], written_ts.data[k], err_msg=err_msg) + assert_allclose( + orig_ts.data[k], written_ts.data[k], err_msg=err_msg + ) class _GromacsWriterIssue101(object): @@ -783,7 +807,9 @@ def test_lambda(self, ref, universe, tmpdir): reader = ref.reader(outfile) for i, ts in enumerate(reader): - assert_almost_equal(ts.data["lambda"], i / float(reader.n_frames)) + assert_almost_equal( + ts.data["lambda"], i / float(reader.n_frames) + ) class _GromacsReader_offsets(object): @@ -859,7 +885,9 @@ def test_nonexistent_offsets_file(self, traj): np_load_mock.side_effect = IOError with pytest.warns( UserWarning, - match=re.escape(f"Failed to load offsets file {outfile_offsets}"), + match=re.escape( + f"Failed to load offsets file {outfile_offsets}" + ), ): saved_offsets = XDR.read_numpy_offsets(outfile_offsets) assert saved_offsets == False @@ -872,7 +900,9 @@ def test_corrupted_offsets_file(self, traj): np_load_mock.side_effect = ValueError with pytest.warns( UserWarning, - match=re.escape(f"Failed to load offsets file {outfile_offsets}"), + match=re.escape( + f"Failed to load offsets file {outfile_offsets}" + ), ): saved_offsets = XDR.read_numpy_offsets(outfile_offsets) assert saved_offsets == False diff --git a/testsuite/MDAnalysisTests/core/test_accessors.py b/testsuite/MDAnalysisTests/core/test_accessors.py index cc59f11ddb..8084fa105a 100644 --- a/testsuite/MDAnalysisTests/core/test_accessors.py +++ b/testsuite/MDAnalysisTests/core/test_accessors.py @@ -53,13 +53,18 @@ def test_convert_to_lib_method_kwargs(self, u): class TestAccessor: def test_access_from_class(self): - assert mda.core.AtomGroup.convert_to is mda.core.accessors.ConverterWrapper + assert ( + mda.core.AtomGroup.convert_to + is mda.core.accessors.ConverterWrapper + ) class TestConverterWrapper: def test_raises_valueerror(self): u = mda.Universe.empty(1) - with pytest.raises(ValueError, match="No 'mdanalysis' converter found"): + with pytest.raises( + ValueError, match="No 'mdanalysis' converter found" + ): u.atoms.convert_to("mdanalysis") @requires_rdkit diff --git a/testsuite/MDAnalysisTests/core/test_accumulate.py b/testsuite/MDAnalysisTests/core/test_accumulate.py index b43bf0b008..2aa1fd2909 100644 --- a/testsuite/MDAnalysisTests/core/test_accumulate.py +++ b/testsuite/MDAnalysisTests/core/test_accumulate.py @@ -41,7 +41,9 @@ def group(self, request): return getattr(u, request.param) def test_accumulate_str_attribute(self, group): - assert_almost_equal(group.accumulate("masses"), np.sum(group.atoms.masses)) + assert_almost_equal( + group.accumulate("masses"), np.sum(group.atoms.masses) + ) def test_accumulate_different_func(self, group): assert_almost_equal( @@ -112,7 +114,9 @@ def test_accumulate_array_attribute_compounds(self, name, compound, level): for a in group.atoms.groupby(name).values() ] assert_equal( - group.accumulate(np.ones((len(group.atoms), 2, 5)), compound=compound), + group.accumulate( + np.ones((len(group.atoms), 2, 5)), compound=compound + ), ref, ) @@ -263,7 +267,9 @@ def test_dipole_moment_residues_com_coc(self, group): def test_dipole_moment_segment(self, methane): compound = "segments" - (_, _, n_compounds) = methane.atoms._split_by_compound_indices(compound) + (_, _, n_compounds) = methane.atoms._split_by_compound_indices( + compound + ) dipoles = methane.dipole_moment(compound=compound, unwrap=True) assert_almost_equal(dipoles, [0.0]) and len(dipoles) == n_compounds @@ -307,9 +313,13 @@ def test_quadrupole_moment_residues(self, group): def test_quadrupole_moment_segment(self, methane): compound = "segments" - (_, _, n_compounds) = methane.atoms._split_by_compound_indices(compound) + (_, _, n_compounds) = methane.atoms._split_by_compound_indices( + compound + ) quadrupoles = methane.quadrupole_moment(compound=compound, unwrap=True) - assert_almost_equal(quadrupoles, [0.0]) and len(quadrupoles) == n_compounds + assert_almost_equal(quadrupoles, [0.0]) and len( + quadrupoles + ) == n_compounds def test_quadrupole_moment_fragments(self, group): compound = "fragments" diff --git a/testsuite/MDAnalysisTests/core/test_atom.py b/testsuite/MDAnalysisTests/core/test_atom.py index 83080ce4b4..1d114c5a17 100644 --- a/testsuite/MDAnalysisTests/core/test_atom.py +++ b/testsuite/MDAnalysisTests/core/test_atom.py @@ -73,7 +73,9 @@ def test_setting_attributes_charge(self, atom): assert atom.charge == 6 def test_attributes_positions(self, atom): - known_pos = np.array([3.94543672, -12.4060812, -7.26820087], dtype=np.float32) + known_pos = np.array( + [3.94543672, -12.4060812, -7.26820087], dtype=np.float32 + ) a = atom # new position property (mutable) assert_almost_equal(a.position, known_pos) diff --git a/testsuite/MDAnalysisTests/core/test_atomgroup.py b/testsuite/MDAnalysisTests/core/test_atomgroup.py index 99f05d7619..38432e65c4 100644 --- a/testsuite/MDAnalysisTests/core/test_atomgroup.py +++ b/testsuite/MDAnalysisTests/core/test_atomgroup.py @@ -87,7 +87,9 @@ def test_improper(self, u): imp = ag.improper assert isinstance(imp, ImproperDihedral) - @pytest.mark.parametrize("btype,", ["bond", "angle", "dihedral", "improper"]) + @pytest.mark.parametrize( + "btype,", ["bond", "angle", "dihedral", "improper"] + ) def test_VE(self, btype, u): ag = u.atoms[:10] with pytest.raises(ValueError): @@ -133,7 +135,9 @@ def test_write_frames(self, u, tmpdir, frames): u.atoms.write(destination, frames=frames) u_new = mda.Universe(destination, to_guess=()) - new_positions = np.stack([ts.positions.copy() for ts in u_new.trajectory]) + new_positions = np.stack( + [ts.positions.copy() for ts in u_new.trajectory] + ) assert_array_almost_equal(new_positions, ref_positions) @@ -152,7 +156,9 @@ def test_write_frame_iterator(self, u, tmpdir, frames): u.atoms.write(destination, frames=selection) u_new = mda.Universe(destination, to_guess=()) - new_positions = np.stack([ts.positions.copy() for ts in u_new.trajectory]) + new_positions = np.stack( + [ts.positions.copy() for ts in u_new.trajectory] + ) assert_array_almost_equal(new_positions, ref_positions) @@ -175,7 +181,9 @@ def test_write_frames_all(self, u, tmpdir, compression): u_new = mda.Universe(destination, to_guess=()) ref_positions = np.stack([ts.positions.copy() for ts in u.trajectory]) - new_positions = np.stack([ts.positions.copy() for ts in u_new.trajectory]) + new_positions = np.stack( + [ts.positions.copy() for ts in u_new.trajectory] + ) assert_array_almost_equal(new_positions, ref_positions) @pytest.mark.parametrize("frames", ("invalid", 8, True, False, 3.2)) @@ -272,7 +280,9 @@ def test_write_selection(self, universe, outfile, selection): def test_write_Residue(self, universe, outfile): G = ( - universe.select_atoms("segid 4AKE and resname ARG").residues[-2].atoms + universe.select_atoms("segid 4AKE and resname ARG") + .residues[-2] + .atoms ) # 2nd to last Arg G.write(outfile) u2 = self.universe_from_tmp(outfile) @@ -285,7 +295,8 @@ def test_write_Residue(self, universe, outfile): G2.positions, G.positions, self.precision, - err_msg="written Residue R206 coordinates do not " "agree with original", + err_msg="written Residue R206 coordinates do not " + "agree with original", ) def test_write_Universe(self, universe, outfile): @@ -294,13 +305,16 @@ def test_write_Universe(self, universe, outfile): W.write(U) u2 = self.universe_from_tmp(outfile) assert len(u2.atoms) == len(U.atoms), ( - "written 4AKE universe does " "not match original universe " "in size" + "written 4AKE universe does " + "not match original universe " + "in size" ) assert_almost_equal( u2.atoms.positions, U.atoms.positions, self.precision, - err_msg="written universe 4AKE coordinates do not " "agree with original", + err_msg="written universe 4AKE coordinates do not " + "agree with original", ) @@ -362,7 +376,9 @@ def test_rotate(self, u, coords): ag.positions = vec.copy() res_ag = ag.rotate(R[:3, :3]) assert_equal(ag, res_ag) - assert_almost_equal(ag.positions[0], [np.cos(angle), np.sin(angle), 0]) + assert_almost_equal( + ag.positions[0], [np.cos(angle), np.sin(angle), 0] + ) ag.positions = vec.copy() ag.rotate(R[:3, :3], vec[0]) @@ -389,7 +405,9 @@ def test_rotateby(self, u, coords): # needs to be rotated about origin res_ag = ag.rotateby(np.rad2deg(angle), axis) assert_equal(res_ag, ag) - assert_almost_equal(ag.positions[0], [np.cos(angle), np.sin(angle), 0]) + assert_almost_equal( + ag.positions[0], [np.cos(angle), np.sin(angle), 0] + ) ag.positions = vec.copy() ag.rotateby(np.rad2deg(angle), axis, point=vec[0]) @@ -414,7 +432,9 @@ def test_transform_rotation_only(self, u, coords): R = transformations.rotation_matrix(angle, axis) ag.positions = vec.copy() ag.transform(R) - assert_almost_equal(ag.positions[0], [np.cos(angle), np.sin(angle), 0]) + assert_almost_equal( + ag.positions[0], [np.cos(angle), np.sin(angle), 0] + ) def test_transform_translation_only(self, u, center_of_geometry): disp = np.ones(3) @@ -437,7 +457,9 @@ def test_transform_translation_and_rotation(self, u): ag.positions = [[1, 0, 0], [-1, 0, 0]] ag.transform(T) - assert_almost_equal(ag.positions[0], [np.cos(angle) + 1, np.sin(angle) + 1, 1]) + assert_almost_equal( + ag.positions[0], [np.cos(angle) + 1, np.sin(angle) + 1, 1] + ) class TestCenter(object): @@ -498,7 +520,9 @@ def test_center_unwrap(self, level, compound, is_triclinic): group = group.segments # get the expected results - center = group.center(weights=None, wrap=False, compound=compound, unwrap=True) + center = group.center( + weights=None, wrap=False, compound=compound, unwrap=True + ) ref_center = u.center(compound=compound) assert_almost_equal(ref_center, center, decimal=4) @@ -508,7 +532,9 @@ def test_center_unwrap_wrap_true_group(self): # select group appropriate for compound: group = u.atoms[39:47] # molecule 12 with pytest.raises(ValueError): - group.center(weights=None, compound="group", unwrap=True, wrap=True) + group.center( + weights=None, compound="group", unwrap=True, wrap=True + ) class TestSplit(object): @@ -516,7 +542,9 @@ class TestSplit(object): @pytest.fixture() def ag(self): universe = mda.Universe(PSF, DCD) - return universe.select_atoms("resid 1:50 and not resname LYS and " "name CA CB") + return universe.select_atoms( + "resid 1:50 and not resname LYS and " "name CA CB" + ) def test_split_atoms(self, ag): sg = ag.split("atom") @@ -613,7 +641,8 @@ def test_ag_matches_atom(self, att, atts, ag, att_type): assert_equal( ref, getattr(ag, atts), - err_msg="AtomGroup doesn't match Atoms for property: " "{0}".format(att), + err_msg="AtomGroup doesn't match Atoms for property: " + "{0}".format(att), ) @pytest.mark.parametrize("att, atts, att_type", attributes) @@ -1197,7 +1226,9 @@ def test_residues(self, ag, unwrap, ref, method_name): result = method(compound="residues") assert_almost_equal(result, ref[method_name], self.prec) - @pytest.mark.parametrize("unwrap, ref", ((True, ref_Unwrap), (False, ref_noUnwrap))) + @pytest.mark.parametrize( + "unwrap, ref", ((True, ref_Unwrap), (False, ref_noUnwrap)) + ) @pytest.mark.parametrize( "method_name", ( @@ -1296,7 +1327,9 @@ def ag(self): universe = mda.Universe(TRZ_psf, TRZ) return universe.residues[0:3] - @pytest.mark.parametrize("wrap, ref", ((True, ref_PBC), (False, ref_noPBC))) + @pytest.mark.parametrize( + "wrap, ref", ((True, ref_PBC), (False, ref_noPBC)) + ) @pytest.mark.parametrize( "method_name", ( @@ -1430,7 +1463,9 @@ def test_center_of_mass(self, ag): decimal=5, ) - @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) + @pytest.mark.parametrize( + "method_name", ("center_of_geometry", "center_of_mass") + ) def test_center_duplicates(self, ag, method_name): ag2 = ag + ag[0] ref = getattr(ag, method_name)() @@ -1438,7 +1473,9 @@ def test_center_duplicates(self, ag, method_name): assert not np.allclose(getattr(ag2, method_name)(), ref) assert len(w) == 1 - @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) + @pytest.mark.parametrize( + "method_name", ("center_of_geometry", "center_of_mass") + ) @pytest.mark.parametrize( "name, compound", (("resids", "residues"), ("segids", "segments")) ) @@ -1447,30 +1484,43 @@ def test_center_compounds(self, ag, name, compound, method_name): vals = getattr(ag, method_name)(wrap=False, compound=compound) assert_almost_equal(vals, ref, decimal=5) - @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) + @pytest.mark.parametrize( + "method_name", ("center_of_geometry", "center_of_mass") + ) @pytest.mark.parametrize( "name, compound", (("resids", "residues"), ("segids", "segments")) ) @pytest.mark.parametrize("unwrap", (True, False)) - def test_center_compounds_pbc(self, ag, name, compound, unwrap, method_name): + def test_center_compounds_pbc( + self, ag, name, compound, unwrap, method_name + ): ag.dimensions = [50, 50, 50, 90, 90, 90] ref = [ - getattr(a, method_name)(unwrap=unwrap) for a in ag.groupby(name).values() + getattr(a, method_name)(unwrap=unwrap) + for a in ag.groupby(name).values() ] vals = getattr(ag, method_name)(compound=compound, unwrap=unwrap) assert_almost_equal(vals, ref, decimal=5) - @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) + @pytest.mark.parametrize( + "method_name", ("center_of_geometry", "center_of_mass") + ) @pytest.mark.parametrize( "name, compound", (("molnums", "molecules"), ("fragindices", "fragments")), ) - def test_center_compounds_special(self, ag_molfrg, name, compound, method_name): - ref = [getattr(a, method_name)() for a in ag_molfrg.groupby(name).values()] + def test_center_compounds_special( + self, ag_molfrg, name, compound, method_name + ): + ref = [ + getattr(a, method_name)() for a in ag_molfrg.groupby(name).values() + ] vals = getattr(ag_molfrg, method_name)(wrap=False, compound=compound) assert_almost_equal(vals, ref, decimal=5) - @pytest.mark.parametrize("method_name", ("center_of_geometry", "center_of_mass")) + @pytest.mark.parametrize( + "method_name", ("center_of_geometry", "center_of_mass") + ) @pytest.mark.parametrize( "name, compound", (("molnums", "molecules"), ("fragindices", "fragments")), @@ -1484,7 +1534,9 @@ def test_center_compounds_special_pbc( getattr(a, method_name)(unwrap=unwrap) for a in ag_molfrg.groupby(name).values() ] - vals = getattr(ag_molfrg, method_name)(compound=compound, unwrap=unwrap) + vals = getattr(ag_molfrg, method_name)( + compound=compound, unwrap=unwrap + ) assert_almost_equal(vals, ref, decimal=5) def test_center_wrong_compound(self, ag): @@ -1496,7 +1548,9 @@ def test_center_compounds_special_fail(self, ag_no_molfrg, compound): with pytest.raises(NoDataError): ag_no_molfrg.center(weights=None, compound=compound) - @pytest.mark.parametrize("weights", (None, np.array([0.0]), np.array([2.0]))) + @pytest.mark.parametrize( + "weights", (None, np.array([0.0]), np.array([2.0])) + ) @pytest.mark.parametrize( "compound", ("group", "residues", "segments", "molecules", "fragments") ) @@ -1537,14 +1591,18 @@ def test_center_compounds_empty(self, ag_molfrg, wrap, weights, compound): ("fragindices", "fragments"), ), ) - def test_center_compounds_zero_weights(self, ag_molfrg, wrap, name, compound): + def test_center_compounds_zero_weights( + self, ag_molfrg, wrap, name, compound + ): if compound == "group": ref = np.full((3,), np.nan) else: n_compounds = len(ag_molfrg.groupby(name)) ref = np.full((n_compounds, 3), np.nan, dtype=np.float64) weights = np.zeros(len(ag_molfrg)) - assert_equal(ref, ag_molfrg.center(weights, wrap=wrap, compound=compound)) + assert_equal( + ref, ag_molfrg.center(weights, wrap=wrap, compound=compound) + ) def test_coordinates(self, ag): assert_almost_equal( @@ -1727,14 +1785,17 @@ def test_packintobox(self, universe): # Check with duplicates: ag += ag ag.pack_into_box(box=box) - assert_almost_equal(ag.positions, np.vstack((packed_coords, packed_coords))) + assert_almost_equal( + ag.positions, np.vstack((packed_coords, packed_coords)) + ) def test_residues(self, universe): u = universe assert_equal( u.residues[100].atoms.ix, u.select_atoms("resname ILE and resid 101").atoms.ix, - "Direct selection from residue group does not match " "expected I101.", + "Direct selection from residue group does not match " + "expected I101.", ) def test_index_integer(self, universe): @@ -2012,7 +2073,9 @@ def test_sort(self, ag, inputs, expected): assert np.array_equal(expected, agsort.ix) def test_sort_bonds(self, ag): - with pytest.raises(ValueError, match=r"The array returned by the " "attribute"): + with pytest.raises( + ValueError, match=r"The array returned by the " "attribute" + ): ag.sort("bonds") def test_sort_positions_2D(self, ag): diff --git a/testsuite/MDAnalysisTests/core/test_atomselections.py b/testsuite/MDAnalysisTests/core/test_atomselections.py index e69e220a6b..f7d0c5fc10 100644 --- a/testsuite/MDAnalysisTests/core/test_atomselections.py +++ b/testsuite/MDAnalysisTests/core/test_atomselections.py @@ -119,7 +119,9 @@ def test_resid_single(self, universe): def test_resid_range(self, universe): sel = universe.select_atoms("resid 100:105") assert_equal(sel.n_atoms, 89) - assert_equal(sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"]) + assert_equal( + sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"] + ) def test_selgroup(self, universe): sel = universe.select_atoms("not resid 100") @@ -146,15 +148,23 @@ def test_resnum_range(self, universe): sel = universe.select_atoms("resnum 100:105") assert_equal(sel.n_atoms, 89) assert_equal(sel.residues.resids, range(100, 106)) - assert_equal(sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"]) + assert_equal( + sel.residues.resnames, ["GLY", "ILE", "ASN", "VAL", "ASP", "TYR"] + ) def test_resname(self, universe): sel = universe.select_atoms("resname LEU") - assert_equal(sel.n_atoms, 304, "Failed to find all 'resname LEU' atoms.") - assert_equal(sel.n_residues, 16, "Failed to find all 'resname LEU' residues.") + assert_equal( + sel.n_atoms, 304, "Failed to find all 'resname LEU' atoms." + ) + assert_equal( + sel.n_residues, 16, "Failed to find all 'resname LEU' residues." + ) assert_equal( sorted(sel.indices), - sorted(universe.select_atoms("segid 4AKE and resname LEU").indices), + sorted( + universe.select_atoms("segid 4AKE and resname LEU").indices + ), "selected 'resname LEU' atoms are not the same as auto-generated s4AKE.LEU", ) @@ -168,7 +178,9 @@ def test_atom(self, universe): assert_equal(sel.resnames, ["GLY"]) assert_equal( sel.positions, - np.array([[20.38685226, -3.44224262, -5.92158318]], dtype=np.float32), + np.array( + [[20.38685226, -3.44224262, -5.92158318]], dtype=np.float32 + ), ) def test_atom_empty(self, universe): @@ -310,7 +322,10 @@ def test_same_resname(self, universe): assert_equal( len(sel), 331, - ("Found a wrong number of atoms with same resname as " "resids 10 or 11"), + ( + "Found a wrong number of atoms with same resname as " + "resids 10 or 11" + ), ) # fmt: off target_resids = np.array( @@ -405,7 +420,9 @@ def test_no_space_around_parentheses(self, universe): def test_concatenated_selection(self, universe): E151 = universe.select_atoms("segid 4AKE").select_atoms("resid 151") # note that this is not quite phi... HN should be C of prec. residue - phi151 = E151.atoms.select_atoms("name HN", "name N", "name CA", "name CB") + phi151 = E151.atoms.select_atoms( + "name HN", "name N", "name CA", "name CB" + ) assert_equal(len(phi151), 4) assert_equal( phi151[0].name, @@ -417,7 +434,9 @@ def test_global(self, universe): """Test the `global` modifier keyword (Issue 268)""" ag = universe.select_atoms("resname LYS and name NZ") # Lys amines within 4 angstrom of the backbone. - ag1 = universe.select_atoms("resname LYS and name NZ and around 4 backbone") + ag1 = universe.select_atoms( + "resname LYS and name NZ and around 4 backbone" + ) ag2 = ag.select_atoms("around 4 global backbone") assert_equal(ag2.indices, ag1.indices) @@ -468,8 +487,12 @@ def universe(self): def test_protein(self, universe): # must include non-standard residues sel = universe.select_atoms("protein or resname HAO or resname ORT") - assert_equal(sel.n_atoms, universe.atoms.n_atoms, "failed to select peptide") - assert_equal(sel.n_residues, 6, "failed to select all peptide residues") + assert_equal( + sel.n_atoms, universe.atoms.n_atoms, "failed to select peptide" + ) + assert_equal( + sel.n_residues, 6, "failed to select all peptide residues" + ) def test_resid_single(self, universe): sel = universe.select_atoms("resid 12") @@ -559,7 +582,9 @@ def test_same_fragment(self, universe, selstr): # This test comes here because it's a system with solvent, # and thus multiple fragments. sel = universe.select_atoms(selstr) - errmsg = "Found a wrong number of atoms " "on the same fragment as id 1" + errmsg = ( + "Found a wrong number of atoms " "on the same fragment as id 1" + ) assert_equal(len(sel), 3341, errmsg) errmsg = ( "Found a differ set of atoms when using the 'same " @@ -662,7 +687,9 @@ def test_passing_rdkit_kwargs_to_converter(self): def test_passing_max_matches_to_converter(self, u2): with pytest.warns(UserWarning, match="Your smarts-based") as wsmg: sel = u2.select_atoms("smarts C", smarts_kwargs=dict(maxMatches=2)) - sel2 = u2.select_atoms("smarts C", smarts_kwargs=dict(maxMatches=1000)) + sel2 = u2.select_atoms( + "smarts C", smarts_kwargs=dict(maxMatches=1000) + ) assert sel.n_atoms == 2 assert sel2.n_atoms == 3 @@ -873,7 +900,9 @@ class TestOrthogonalDistanceSelections(BaseDistanceSelection): def u(self): return mda.Universe(TRZ_psf, TRZ) - @pytest.mark.parametrize("meth, periodic", [("distmat", True), ("distmat", False)]) + @pytest.mark.parametrize( + "meth, periodic", [("distmat", True), ("distmat", False)] + ) def test_cyzone(self, u, meth, periodic): sel = Parser.parse("cyzone 5 4 -4 resid 2", u.atoms) sel.periodic = periodic @@ -1141,7 +1170,9 @@ def test_flip(self, prop, ag, op): # reference group, doing things forwards ref = ag[func(getattr(ag, self.plurals[prop]), 1.5)] - selstr = "prop 1.5 {op} {prop}".format(op=self.opposites[op], prop=prop) + selstr = "prop 1.5 {op} {prop}".format( + op=self.opposites[op], prop=prop + ) sel = ag.select_atoms(selstr) assert_equal(set(ref.indices), set(sel.indices)) @@ -1172,7 +1203,9 @@ class TestSelectionErrors(object): @staticmethod @pytest.fixture() def universe(): - return make_Universe(("names", "masses", "resids", "resnames", "resnums")) + return make_Universe( + ("names", "masses", "resids", "resnames", "resnums") + ) @pytest.mark.parametrize( "selstr", @@ -1274,7 +1307,9 @@ def test_string_selections(self, ref, sel, universe): ], ) def test_range_selections(self, seltype, ref, sel, universe): - self._check_sels(ref.format(typ=seltype), sel.format(typ=seltype), universe) + self._check_sels( + ref.format(typ=seltype), sel.format(typ=seltype), universe + ) class TestICodeSelection(object): @@ -1617,7 +1652,9 @@ def test_bool_sel_error(): def test_error_selection_for_strange_dtype(): with pytest.raises(ValueError, match="No base class defined for dtype"): - MDAnalysis.core.selection.gen_selection_class("star", "stars", dict, "atom") + MDAnalysis.core.selection.gen_selection_class( + "star", "stars", dict, "atom" + ) @pytest.mark.parametrize( @@ -1684,7 +1721,9 @@ def test_chirality(smi, chirality): assert u.atoms[0].chirality == "" assert u.atoms[1].chirality == chirality - assert_equal(u.atoms[:3].chiralities, np.array(["", chirality, ""], dtype="U1")) + assert_equal( + u.atoms[:3].chiralities, np.array(["", chirality, ""], dtype="U1") + ) @pytest.mark.parametrize( diff --git a/testsuite/MDAnalysisTests/core/test_group_traj_access.py b/testsuite/MDAnalysisTests/core/test_group_traj_access.py index 0939f52b56..f7061177f4 100644 --- a/testsuite/MDAnalysisTests/core/test_group_traj_access.py +++ b/testsuite/MDAnalysisTests/core/test_group_traj_access.py @@ -125,7 +125,9 @@ def test_atomgroup_velocities_access(self, u, vel): else: with pytest.raises(NoDataError): getattr(ag, "velocities") - assert_correct_errormessage((getattr, ag, "velocities"), "velocities") + assert_correct_errormessage( + (getattr, ag, "velocities"), "velocities" + ) def test_atomgroup_forces_access(self, u, force): ag = u.atoms[10:20] @@ -165,7 +167,9 @@ def test_atom_velocity_access(self, u, vel): else: with pytest.raises(NoDataError): getattr(at, "velocity") - assert_correct_errormessage((getattr, at, "velocity"), "velocities") + assert_correct_errormessage( + (getattr, at, "velocity"), "velocities" + ) def test_atom_force_access(self, u, force): at = u.atoms[55] @@ -185,18 +189,25 @@ def test_atom_force_access(self, u, force): def test_atomgroup_positions_setting(self, u): ag = u.atoms[[101, 107, 109]] - new = np.array([[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]]) + new = np.array( + [[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]] + ) ag.positions = new assert_almost_equal(ag.positions, new, decimal=5) - assert_almost_equal(u.trajectory.ts.positions[[101, 107, 109]], new, decimal=5) + assert_almost_equal( + u.trajectory.ts.positions[[101, 107, 109]], new, decimal=5 + ) def test_atomgroup_velocities_setting(self, u, vel): ag = u.atoms[[101, 107, 109]] new = ( - np.array([[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]]) + 0.1 + np.array( + [[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]] + ) + + 0.1 ) if vel: @@ -209,20 +220,27 @@ def test_atomgroup_velocities_setting(self, u, vel): else: with pytest.raises(NoDataError): setattr(ag, "velocities", new) - assert_correct_errormessage((setattr, ag, "velocities", new), "velocities") + assert_correct_errormessage( + (setattr, ag, "velocities", new), "velocities" + ) def test_atomgroup_forces_setting(self, u, force): ag = u.atoms[[101, 107, 109]] new = ( - np.array([[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]]) + 0.2 + np.array( + [[72.4, 64.5, 74.7], [124.6, 15.6, -1.11], [25.2, -66.6, 0]] + ) + + 0.2 ) if force: ag.forces = new assert_almost_equal(ag.forces, new, decimal=5) - assert_almost_equal(u.trajectory.ts.forces[[101, 107, 109]], new, decimal=5) + assert_almost_equal( + u.trajectory.ts.forces[[101, 107, 109]], new, decimal=5 + ) else: with pytest.raises(NoDataError): setattr(ag, "forces", new) @@ -251,7 +269,9 @@ def test_atom_velocity_setting(self, u, vel): else: with pytest.raises(NoDataError): setattr(at, "velocity", new) - assert_correct_errormessage((setattr, at, "velocity", new), "velocities") + assert_correct_errormessage( + (setattr, at, "velocity", new), "velocities" + ) def test_atom_force_setting(self, u, force): at = u.atoms[94] @@ -459,7 +479,9 @@ def test_velocities(self, universe): ] ) v = ag.velocities - assert_almost_equal(v, ref_v, err_msg="velocities were not read correctly") + assert_almost_equal( + v, ref_v, err_msg="velocities were not read correctly" + ) def test_set_velocities(self, ag): ag = ag @@ -494,4 +516,6 @@ def test_forces(self, universe): def test_set_forces(self, ag): v = ag.forces - 2.7271 ag.forces = v - assert_almost_equal(ag.forces, v, err_msg="messages were not set to new value") + assert_almost_equal( + ag.forces, v, err_msg="messages were not set to new value" + ) diff --git a/testsuite/MDAnalysisTests/core/test_groups.py b/testsuite/MDAnalysisTests/core/test_groups.py index ef8c8c85e8..7cd890b046 100644 --- a/testsuite/MDAnalysisTests/core/test_groups.py +++ b/testsuite/MDAnalysisTests/core/test_groups.py @@ -142,7 +142,9 @@ def test_create_unique_group_from_unique(self, group): # check if caches of group.sorted_unique have been set correctly: assert group.sorted_unique._cache["isunique"] is True - assert group.sorted_unique._cache["sorted_unique"] is group.sorted_unique + assert ( + group.sorted_unique._cache["sorted_unique"] is group.sorted_unique + ) # assert that repeated access yields the same object (not a copy): unique_group = group.sorted_unique assert unique_group is group.sorted_unique @@ -507,7 +509,9 @@ def test_sum(self, a, b, c, refclass): assert_equal( len(summed), len(self.itr(a)) + len(self.itr(b)) + len(self.itr(c)) ) - for x, y in zip(summed, itertools.chain(self.itr(a), self.itr(b), self.itr(c))): + for x, y in zip( + summed, itertools.chain(self.itr(a), self.itr(b), self.itr(c)) + ): assert x == y @pytest.mark.parametrize( @@ -527,7 +531,11 @@ def test_contains_false(self, group): @pytest.mark.parametrize( "one_level, other_level", - [(l1, l2) for l1, l2 in itertools.product(levels, repeat=2) if l1 != l2], + [ + (l1, l2) + for l1, l2 in itertools.product(levels, repeat=2) + if l1 != l2 + ], ) def test_contains_wronglevel(self, one_level, other_level): group = self.group_dict[one_level] @@ -985,7 +993,8 @@ def u(self): def test_atom_repr(self, u): at = u.atoms[0] assert ( - repr(at) == "" + repr(at) + == "" ) def test_residue_repr(self, u): @@ -1009,7 +1018,9 @@ def test_atomgroup_str_short(self, u): def test_atomgroup_str_long(self, u): ag = u.atoms[:11] - assert str(ag).startswith("]>") @@ -1111,7 +1122,9 @@ def test_len(self, groups_simple): assert_equal(len(d), 0) assert_equal(len(e), 3) - def test_len_duplicated_and_scrambled(self, groups_duplicated_and_scrambled): + def test_len_duplicated_and_scrambled( + self, groups_duplicated_and_scrambled + ): a, b, c, d, e = groups_duplicated_and_scrambled assert_equal(len(a), 7) assert_equal(len(b), 8) @@ -1124,9 +1137,13 @@ def test_equal(self, groups): assert a == a assert a != b assert not a == b - assert not a[0:1] == a[0], "Element should not equal single element group." + assert ( + not a[0:1] == a[0] + ), "Element should not equal single element group." - @pytest.mark.parametrize("group", (u.atoms[:2], u.residues[:2], u.segments[:2])) + @pytest.mark.parametrize( + "group", (u.atoms[:2], u.residues[:2], u.segments[:2]) + ) def test_copy(self, group): # make sure uniqueness caches of group are empty: with pytest.raises(KeyError): @@ -1382,7 +1399,9 @@ def test_hash_difference(self, u, level): b = getattr(u, level)[1:] assert hash(a) != hash(b) - @pytest.mark.parametrize("level_a, level_b", itertools.permutations(levels, 2)) + @pytest.mark.parametrize( + "level_a, level_b", itertools.permutations(levels, 2) + ) def test_hash_difference_cross(self, u, level_a, level_b): a = getattr(u, level_a)[0:-1] b = getattr(u, level_b)[0:-1] @@ -1560,7 +1579,9 @@ def test_unwrap_without_bonds(self, universe): def test_get_absent_attr_method(self, universe): with pytest.raises(NoDataError) as exc: universe.atoms.total_charge() - err = "AtomGroup.total_charge() not available; " "this requires charges" + err = ( + "AtomGroup.total_charge() not available; " "this requires charges" + ) assert str(exc.value) == err def test_get_absent_attrprop(self, universe): @@ -1585,7 +1606,9 @@ def test_attrmethod_wrong_group(self, universe): def test_wrong_name(self, universe, attr): with pytest.raises(AttributeError) as exc: getattr(universe.atoms, attr) - err = ("AtomGroup has no attribute {}. " "Did you mean altLocs?").format(attr) + err = ( + "AtomGroup has no attribute {}. " "Did you mean altLocs?" + ).format(attr) assert str(exc.value) == err @@ -1662,7 +1685,9 @@ def test_wrap_and_unwrap_deprecation(self, compound, pbc, unwrap): # deprecation. We need to tell the linter. assert ( # pylint: disable-next=unexpected-keyword-arg - self.dummy_funtion(compound=compound, pbc=pbc, unwrap=unwrap) + self.dummy_funtion( + compound=compound, pbc=pbc, unwrap=unwrap + ) == 0 ) @@ -1677,7 +1702,10 @@ def test_wrap_and_unwrap(self, compound, wrap, unwrap): with pytest.raises(ValueError): self.dummy_funtion(compound=compound, wrap=wrap, unwrap=unwrap) else: - assert self.dummy_funtion(compound=compound, wrap=wrap, unwrap=unwrap) == 0 + assert ( + self.dummy_funtion(compound=compound, wrap=wrap, unwrap=unwrap) + == 0 + ) @pytest.fixture() @@ -1690,7 +1718,9 @@ def tpr(): class TestGetConnectionsAtoms(object): """Test Atom and AtomGroup.get_connections""" - @pytest.mark.parametrize("typename", ["bonds", "angles", "dihedrals", "impropers"]) + @pytest.mark.parametrize( + "typename", ["bonds", "angles", "dihedrals", "impropers"] + ) def test_connection_from_atom_not_outside(self, tpr, typename): cxns = tpr.atoms[1].get_connections(typename, outside=False) assert len(cxns) == 0 @@ -1788,7 +1818,9 @@ def test_connection_from_res_outside(self, tpr, typename, n_atoms): ("dihedrals", 351), ], ) - def test_connection_from_residues_not_outside(self, tpr, typename, n_atoms): + def test_connection_from_residues_not_outside( + self, tpr, typename, n_atoms + ): ag = tpr.residues[:10] cxns = ag.get_connections(typename, outside=False) assert len(cxns) == n_atoms diff --git a/testsuite/MDAnalysisTests/core/test_residuegroup.py b/testsuite/MDAnalysisTests/core/test_residuegroup.py index 4a2efc9469..06d0e22e9a 100644 --- a/testsuite/MDAnalysisTests/core/test_residuegroup.py +++ b/testsuite/MDAnalysisTests/core/test_residuegroup.py @@ -56,7 +56,9 @@ def u(self): def test_string(self, u): p = u.select_atoms("protein") - assert_equal(p.residues.sequence(format="string"), self.ref_adk_sequence) + assert_equal( + p.residues.sequence(format="string"), self.ref_adk_sequence + ) def test_SeqRecord(self, u): p = u.select_atoms("protein") @@ -188,7 +190,8 @@ def test_set_resids_updates_self(self, universe): assert_equal( rg.resids, resids, - err_msg="old selection was not changed in place " "after set_resid", + err_msg="old selection was not changed in place " + "after set_resid", ) def test_set_resnum_single(self, universe): @@ -294,7 +297,9 @@ def test_set_masses(self, universe): assert_equal( [a.mass for a in rg.atoms], mass * np.ones(rg.n_atoms), - err_msg="failed to set_mass H* atoms in resid 12:42 to {0}".format(mass), + err_msg="failed to set_mass H* atoms in resid 12:42 to {0}".format( + mass + ), ) # VALID diff --git a/testsuite/MDAnalysisTests/core/test_topology.py b/testsuite/MDAnalysisTests/core/test_topology.py index b34666f774..d1154f5c4e 100644 --- a/testsuite/MDAnalysisTests/core/test_topology.py +++ b/testsuite/MDAnalysisTests/core/test_topology.py @@ -722,7 +722,9 @@ def names(self): @pytest.fixture() def types(self): - return ta.Atomtypes(np.array(["X", "Y", "Z"], dtype=object), guessed=True) + return ta.Atomtypes( + np.array(["X", "Y", "Z"], dtype=object), guessed=True + ) @pytest.fixture() def resids(self): diff --git a/testsuite/MDAnalysisTests/core/test_topologyattrs.py b/testsuite/MDAnalysisTests/core/test_topologyattrs.py index 4be0bcb764..5155933c2e 100644 --- a/testsuite/MDAnalysisTests/core/test_topologyattrs.py +++ b/testsuite/MDAnalysisTests/core/test_topologyattrs.py @@ -233,7 +233,9 @@ class AggregationMixin(TestAtomAttr): def test_get_residues(self, attr): assert_equal( attr.get_residues(DummyGroup([2, 1])), - np.array([self.values[[2, 3, 9]].sum(), self.values[[4, 5, 8]].sum()]), + np.array( + [self.values[[2, 3, 9]].sum(), self.values[[4, 5, 8]].sum()] + ), ) def test_get_segments(self, attr): @@ -279,7 +281,9 @@ def test_set_residue_VE(self, universe): setattr(res, self.attrclass.singular, self.values[:2]) def test_get_atoms(self, attr): - assert_equal(attr.get_atoms(DummyGroup([7, 3, 9])), self.values[[3, 2, 2]]) + assert_equal( + attr.get_atoms(DummyGroup([7, 3, 9])), self.values[[3, 2, 2]] + ) def test_get_atom(self, universe): attr = getattr(universe.atoms[0], self.attrclass.singular) @@ -371,7 +375,9 @@ def test_set_segment_VE(self): setattr(seg, "segid", [1, 2, 3]) def test_get_atoms(self, attr): - assert_equal(attr.get_atoms(DummyGroup([2, 4, 1])), self.values[[1, 1, 0]]) + assert_equal( + attr.get_atoms(DummyGroup([2, 4, 1])), self.values[[1, 1, 0]] + ) def test_get_residues(self, attr): assert_equal( @@ -384,7 +390,9 @@ def test_get_segments(self, attr): atoms in segments. """ - assert_equal(attr.get_segments(DummyGroup([1, 0, 0])), self.values[[1, 0, 0]]) + assert_equal( + attr.get_segments(DummyGroup([1, 0, 0])), self.values[[1, 0, 0]] + ) def test_set_segments_singular(self, attr): dg = DummyGroup([0, 1]) @@ -426,7 +434,9 @@ def universe_pa(self): def test_principal_axes_handedness(self, universe_pa): e_vec = universe_pa.atoms.principal_axes() - assert_almost_equal(np.dot(np.cross(e_vec[0], e_vec[1]), e_vec[2]), 1.0) + assert_almost_equal( + np.dot(np.cross(e_vec[0], e_vec[1]), e_vec[2]), 1.0 + ) def test_align_principal_axes_with_self(self, ag): pa = ag.principal_axes() diff --git a/testsuite/MDAnalysisTests/core/test_topologyobjects.py b/testsuite/MDAnalysisTests/core/test_topologyobjects.py index 7c54eeb16e..196b91364d 100644 --- a/testsuite/MDAnalysisTests/core/test_topologyobjects.py +++ b/testsuite/MDAnalysisTests/core/test_topologyobjects.py @@ -221,7 +221,9 @@ def test_ureybradley_partner(self, PSFDCD): assert ub.partner(PSFDCD.atoms[10]) == PSFDCD.atoms[30] def test_ureybradley_distance(self, b): - assert_almost_equal(b.atoms.ureybradley.distance(), b.length(), self.precision) + assert_almost_equal( + b.atoms.ureybradley.distance(), b.length(), self.precision + ) def test_cmap_repr(self, PSFDCD): cmap = PSFDCD.atoms[[4, 7, 8, 1, 2]].cmap @@ -297,7 +299,9 @@ def test_bond_uniqueness(self, PSFDCD): bondtypes = PSFDCD.atoms.bonds.types() # check that a key doesn't appear in reversed format in keylist # have to exclude case of b[::-1] == b as this is false positive - assert not any([b[::-1] in bondtypes for b in bondtypes if b[::-1] != b]) + assert not any( + [b[::-1] in bondtypes for b in bondtypes if b[::-1] != b] + ) def test_bond_reversal(self, PSFDCD, b_td): bondtypes = PSFDCD.atoms.bonds.types() @@ -435,7 +439,9 @@ def test_create_TopologyGroup(self, res1, PSFDCD): res1_tg2 = res1.atoms.bonds.select_bonds(("23", "3")) assert res1_tg == res1_tg2 - @pytest.mark.parametrize("attr", ["bonds", "angles", "dihedrals", "impropers"]) + @pytest.mark.parametrize( + "attr", ["bonds", "angles", "dihedrals", "impropers"] + ) def test_TG_loose_intersection(self, PSFDCD, attr): """Pull bonds from a TG which are at least partially in an AG""" ag = PSFDCD.atoms[10:60] @@ -480,7 +486,9 @@ def manual(topg, atomg): # dihedrals assert check_strict_intersection(PSFDCD.atoms.dihedrals, testinput) assert manual(PSFDCD.atoms.dihedrals, testinput) == set( - PSFDCD.atoms.dihedrals.atomgroup_intersection(testinput, strict=True) + PSFDCD.atoms.dihedrals.atomgroup_intersection( + testinput, strict=True + ) ) def test_add_TopologyGroups(self, res1, res2, PSFDCD): diff --git a/testsuite/MDAnalysisTests/core/test_universe.py b/testsuite/MDAnalysisTests/core/test_universe.py index 5299d3787f..d931966b42 100644 --- a/testsuite/MDAnalysisTests/core/test_universe.py +++ b/testsuite/MDAnalysisTests/core/test_universe.py @@ -100,7 +100,9 @@ def test_load(self): def test_load_topology_stringio(self): u = mda.Universe(StringIO(CHOL_GRO), format="GRO") - assert_equal(len(u.atoms), 8, "Loading universe from StringIO failed somehow") + assert_equal( + len(u.atoms), 8, "Loading universe from StringIO failed somehow" + ) assert_equal( u.trajectory.ts.positions[0], np.array([65.580002, 29.360001, 40.050003], dtype=np.float32), @@ -113,7 +115,9 @@ def test_load_trajectory_stringio(self): format="GRO", topology_format="GRO", ) - assert_equal(len(u.atoms), 8, "Loading universe from StringIO failed somehow") + assert_equal( + len(u.atoms), 8, "Loading universe from StringIO failed somehow" + ) def test_make_universe_stringio_no_format(self): # Loading from StringIO without format arg should raise TypeError @@ -173,7 +177,9 @@ def test_Universe_invalidfile_IE_msg(self, tmpdir): else: raise AssertionError - @pytest.mark.skipif(get_userid() == 0, reason="cannot permisssionerror as root") + @pytest.mark.skipif( + get_userid() == 0, reason="cannot permisssionerror as root" + ) def test_Universe_invalidpermissionfile_IE_msg(self, tmpdir): # check for file with invalid permissions (eg. no read access) with tmpdir.as_cwd(): @@ -183,7 +189,9 @@ def test_Universe_invalidpermissionfile_IE_msg(self, tmpdir): if os.name == "nt": subprocess.call( - "icacls {filename} /deny Users:RX".format(filename=temp_file), + "icacls {filename} /deny Users:RX".format( + filename=temp_file + ), shell=True, ) else: @@ -204,7 +212,9 @@ def test_load_new_memory_reader_success(self): prot = u.select_atoms("protein") u2 = mda.Merge(prot) assert ( - u2.load_new([prot.positions], format=mda.coordinates.memory.MemoryReader) + u2.load_new( + [prot.positions], format=mda.coordinates.memory.MemoryReader + ) is u2 ) @@ -213,7 +223,9 @@ def load(): u = mda.Universe(GRO) prot = u.select_atoms("protein") u2 = mda.Merge(prot) - u2.load_new([[prot.positions]], format=mda.coordinates.memory.MemoryReader) + u2.load_new( + [[prot.positions]], format=mda.coordinates.memory.MemoryReader + ) with pytest.raises(TypeError): load() @@ -299,7 +311,9 @@ def test_rdkit_kwargs(self): u1 = mda.Universe.from_smiles("C", rdkit_kwargs=dict(randomSeed=42)) u2 = mda.Universe.from_smiles("C", rdkit_kwargs=dict(randomSeed=51)) with pytest.raises(AssertionError) as e: - assert_equal(u1.trajectory.coordinate_array, u2.trajectory.coordinate_array) + assert_equal( + u1.trajectory.coordinate_array, u2.trajectory.coordinate_array + ) assert "Mismatched elements: 15 / 15 (100%)" in str(e.value) def test_coordinates(self): @@ -316,7 +330,9 @@ def test_coordinates(self): expected = [c.GetPositions() for c in mol.GetConformers()] # now the mda way - u = mda.Universe.from_smiles("C", numConfs=2, rdkit_kwargs=dict(randomSeed=42)) + u = mda.Universe.from_smiles( + "C", numConfs=2, rdkit_kwargs=dict(randomSeed=42) + ) assert u.trajectory.n_frames == 2 assert_allclose(u.trajectory.coordinate_array, expected, rtol=1e-7) @@ -629,7 +645,9 @@ def test_frame_interval_convention(self): array1 = universe1.trajectory.timeseries(step=10) universe2 = mda.Universe(PSF, DCD, in_memory=True, in_memory_step=10) array2 = universe2.trajectory.timeseries() - assert_equal(array1, array2, err_msg="Unexpected differences between arrays.") + assert_equal( + array1, array2, err_msg="Unexpected differences between arrays." + ) def test_slicing_with_start_stop(self): universe = MDAnalysis.Universe(PDB_small, DCD) @@ -734,13 +752,17 @@ class TestCustomReaders(object): def test_custom_reader(self): # check that reader passing works - u = mda.Universe(TRZ_psf, TRZ, format=MDAnalysis.coordinates.TRZ.TRZReader) + u = mda.Universe( + TRZ_psf, TRZ, format=MDAnalysis.coordinates.TRZ.TRZReader + ) assert_equal(len(u.atoms), 8184) def test_custom_reader_singleframe(self): T = MDAnalysis.topology.GROParser.GROParser R = MDAnalysis.coordinates.GRO.GROReader - u = mda.Universe(two_water_gro, two_water_gro, topology_format=T, format=R) + u = mda.Universe( + two_water_gro, two_water_gro, topology_format=T, format=R + ) assert_equal(len(u.atoms), 6) def test_custom_reader_singleframe_2(self): @@ -867,7 +889,9 @@ def test_add_connection_error(self, universe, attr, values): def test_add_attr_length_error(self, universe): with pytest.raises(ValueError): - universe.add_TopologyAttr("masses", np.array([1, 2, 3], dtype=np.float64)) + universe.add_TopologyAttr( + "masses", np.array([1, 2, 3], dtype=np.float64) + ) class TestDelTopologyAttr(object): @@ -1034,14 +1058,20 @@ def test_add_atomgroup_to_populated(self, universe, attr, values): self._check_valid_added_to_populated(universe, attr, values, ag) @pytest.mark.parametrize("attr,values", small_atom_indices) - def test_add_atomgroup_wrong_universe_error(self, universe, empty, attr, values): + def test_add_atomgroup_wrong_universe_error( + self, universe, empty, attr, values + ): ag = [empty.atoms[x] for x in values] self._check_invalid_addition(universe, attr, ag, "different Universes") @pytest.mark.parametrize("attr,values", large_atom_indices) def test_add_topologyobjects_to_populated(self, universe, attr, values): - topologyobjects = [getattr(universe.atoms[x], attr[:-1]) for x in values] - self._check_valid_added_to_populated(universe, attr, values, topologyobjects) + topologyobjects = [ + getattr(universe.atoms[x], attr[:-1]) for x in values + ] + self._check_valid_added_to_populated( + universe, attr, values, topologyobjects + ) @pytest.mark.parametrize("attr,values", small_atom_indices) def test_add_topologyobjects_wrong_universe_error( @@ -1055,7 +1085,9 @@ def test_add_topologygroups_to_populated(self, universe, attr, values): topologygroup = mda.core.topologyobjects.TopologyGroup( np.array(values), universe ) - self._check_valid_added_to_populated(universe, attr, values, topologygroup) + self._check_valid_added_to_populated( + universe, attr, values, topologygroup + ) @pytest.mark.parametrize("attr,values", small_atom_indices) def test_add_topologygroup_wrong_universe_error( @@ -1065,7 +1097,9 @@ def test_add_topologygroup_wrong_universe_error( self._check_invalid_addition(empty, attr, tg, "different Universes") @pytest.mark.parametrize("attr,values", small_atom_indices) - def test_add_topologygroup_different_universe(self, universe, empty, attr, values): + def test_add_topologygroup_different_universe( + self, universe, empty, attr, values + ): tg = mda.core.topologyobjects.TopologyGroup(np.array(values), universe) self._check_valid_added_to_empty(empty, attr, values, tg.to_indices()) @@ -1081,7 +1115,9 @@ def test_add_topologygroup_different_universe(self, universe, empty, attr, value def test_add_wrong_topologygroup_error(self, universe, attr, values): arr = np.array(values) tg = mda.core.topologyobjects.TopologyGroup(arr, universe) - self._check_invalid_addition(universe, attr, tg, "iterable of tuples with") + self._check_invalid_addition( + universe, attr, tg, "iterable of tuples with" + ) @pytest.mark.parametrize( "attr,values", @@ -1096,7 +1132,9 @@ def test_add_wrong_topologygroup_error(self, universe, attr, values): ), ) def test_add_nonexistent_indices_error(self, universe, attr, values): - self._check_invalid_addition(universe, attr, values, "nonexistent atom indices") + self._check_invalid_addition( + universe, attr, values, "nonexistent atom indices" + ) @pytest.mark.parametrize( "attr,n", @@ -1108,9 +1146,9 @@ def test_add_nonexistent_indices_error(self, universe, attr, values): ), ) def test_add_wrong_number_of_atoms_error(self, universe, attr, n): - errmsg = ("{} must be an iterable of " "tuples with {} atom indices").format( - attr, n - ) + errmsg = ( + "{} must be an iterable of " "tuples with {} atom indices" + ).format(attr, n) idx = [(0, 1), (0, 1, 2), (8, 22, 1, 3), (5, 3, 4, 2)] self._check_invalid_addition(universe, attr, idx, errmsg) @@ -1196,7 +1234,10 @@ def _check_valid_deleted(self, u, attr, values, to_delete): not_deleted = [x for x in self.TOP[attr] if list(x) not in values] assert all( - [x in u_attr.indices or x[::-1] in u_attr.indices for x in not_deleted] + [ + x in u_attr.indices or x[::-1] in u_attr.indices + for x in not_deleted + ] ) def _check_invalid_deleted(self, u, attr, to_delete, err_msg): @@ -1214,7 +1255,9 @@ def test_delete_valid_indices(self, universe, attr, values): @pytest.mark.parametrize("attr,values", nonexisting_atom_indices) def test_delete_missing_indices(self, universe, attr, values): - self._check_invalid_deleted(universe, attr, values, "Cannot delete nonexistent") + self._check_invalid_deleted( + universe, attr, values, "Cannot delete nonexistent" + ) @pytest.mark.parametrize("attr,values", existing_atom_indices) def test_delete_valid_atomgroup(self, universe, attr, values): @@ -1231,7 +1274,9 @@ def test_delete_atomgroup_wrong_universe_error( @pytest.mark.parametrize("attr,values", nonexisting_atom_indices) def test_delete_missing_atomgroup(self, universe, attr, values): ag = [universe.atoms[x] for x in values] - self._check_invalid_deleted(universe, attr, ag, "Cannot delete nonexistent") + self._check_invalid_deleted( + universe, attr, ag, "Cannot delete nonexistent" + ) @pytest.mark.parametrize("attr,values", existing_atom_indices) def test_delete_mixed_type(self, universe, attr, values): @@ -1249,7 +1294,9 @@ def test_delete_topologyobjects_wrong_universe( ): u1 = [getattr(universe.atoms[x], attr[:-1]) for x in values[:-1]] u2 = [getattr(universe2.atoms[values[-1]], attr[:-1])] - self._check_invalid_deleted(universe, attr, u1 + u2, "different Universes") + self._check_invalid_deleted( + universe, attr, u1 + u2, "different Universes" + ) @pytest.mark.parametrize("attr,values", existing_atom_indices) def test_delete_valid_topologygroup(self, universe, attr, values): @@ -1284,9 +1331,9 @@ def test_delete_topologygroup_different_universe( ) def test_delete_wrong_number_of_atoms_error(self, universe, attr, n): idx = [(0, 1), (0, 1, 2), (8, 22, 1, 3), (5, 3, 4, 2)] - errmsg = ("{} must be an iterable of " "tuples with {} atom indices").format( - attr, n - ) + errmsg = ( + "{} must be an iterable of " "tuples with {} atom indices" + ).format(attr, n) self._check_invalid_deleted(universe, attr, idx, errmsg) @pytest.mark.parametrize("attr,values", existing_atom_indices) @@ -1303,7 +1350,9 @@ def test_delete_bonds_refresh_fragments(self, universe): universe.delete_bonds([universe.atoms[[2, 3]]]) assert len(universe.atoms.fragments) == n_fragments + 1 - @pytest.mark.parametrize("filename, n_bonds", [(CONECT, 72), (PDB_conect, 8)]) + @pytest.mark.parametrize( + "filename, n_bonds", [(CONECT, 72), (PDB_conect, 8)] + ) def test_delete_all_bonds(self, filename, n_bonds): u = mda.Universe(filename) assert len(u.bonds) == n_bonds @@ -1344,12 +1393,16 @@ def u_GRO(self): def test_all_coordinates_length(self, u_GRO_TRR, u_GRO_TRR_allcoords): # length with all_coords should be +1 - assert len(u_GRO_TRR.trajectory) + 1 == len(u_GRO_TRR_allcoords.trajectory) + assert len(u_GRO_TRR.trajectory) + 1 == len( + u_GRO_TRR_allcoords.trajectory + ) def test_all_coordinates_frame(self, u_GRO_TRR_allcoords, u_GRO): # check that first frame in u(GRO, TRR, allcords) # are the coordinates from GRO - assert_array_equal(u_GRO_TRR_allcoords.atoms.positions, u_GRO.atoms.positions) + assert_array_equal( + u_GRO_TRR_allcoords.atoms.positions, u_GRO.atoms.positions + ) def test_second_frame(self, u_GRO_TRR_allcoords, u_GRO_TRR): # check that second frame in u(GRO, TRR, allcoords) @@ -1561,14 +1614,20 @@ def test_set_segments(self, bad_seg, good): assert_equal(["A", "", "A", "B", ""], bad_seg.segments.segids) assert len(bad_seg.residues) == 5 # 5 residues assert_equal([315, 315, 316, 314, 315], bad_seg.residues.resids) - assert_equal(["THR", "THR", "THR", "THR", "THR"], bad_seg.residues.resnames) + assert_equal( + ["THR", "THR", "THR", "THR", "THR"], bad_seg.residues.resnames + ) assert_equal(["A", "", "A", "B", ""], bad_seg.residues.segids) assert len(bad_seg.atoms) == 7 # 7 atoms assert_equal([315, 315, 315, 316, 314, 315, 315], bad_seg.atoms.resids) assert_equal(["THR"] * 7, bad_seg.atoms.resnames) assert_equal(["A", "", "", "A", "B", "", ""], bad_seg.atoms.segids) - assert_equal(["N", "CA", "C", "O", "CB", "CG2", "OG1"], bad_seg.atoms.names) - assert_equal(["A", "A", "A", "A", "B", "B", "B"], bad_seg.atoms.chainIDs) + assert_equal( + ["N", "CA", "C", "O", "CB", "CG2", "OG1"], bad_seg.atoms.names + ) + assert_equal( + ["A", "A", "A", "A", "B", "B", "B"], bad_seg.atoms.chainIDs + ) original_attrs = bad_seg._topology.attrs # [ACT] set new segids @@ -1715,7 +1774,9 @@ def test_with_ITP(self, itp): def test_with_TPR(self, tpr): # [BEFORE] assert len(tpr.segments) == 3 - assert_equal(["seg_0_AKeco", "seg_1_SOL", "seg_2_NA+"], tpr.segments.segids) + assert_equal( + ["seg_0_AKeco", "seg_1_SOL", "seg_2_NA+"], tpr.segments.segids + ) assert len(tpr.residues) == 11302 assert_equal(range(1, 11303, 1), tpr.residues.resids) orignial_res_molnums = tpr.residues.molnums diff --git a/testsuite/MDAnalysisTests/core/test_unwrap.py b/testsuite/MDAnalysisTests/core/test_unwrap.py index ecff4d68f9..e6da223ee2 100644 --- a/testsuite/MDAnalysisTests/core/test_unwrap.py +++ b/testsuite/MDAnalysisTests/core/test_unwrap.py @@ -70,13 +70,17 @@ def test_unwrap_pass(self, level, compound, reference, is_triclinic): if compound == "group": ref_unwrapped_pos = ref_unwrapped_pos[39:47] # molecule 12 elif compound == "segments": - ref_unwrapped_pos = ref_unwrapped_pos[23:47] # molecules 10, 11, 12 + ref_unwrapped_pos = ref_unwrapped_pos[ + 23:47 + ] # molecules 10, 11, 12 # first, do the unwrapping out-of-place: unwrapped_pos = group.unwrap( compound=compound, reference=reference, inplace=False ) # check for correct result: - assert_almost_equal(unwrapped_pos, ref_unwrapped_pos, decimal=self.precision) + assert_almost_equal( + unwrapped_pos, ref_unwrapped_pos, decimal=self.precision + ) # make sure atom positions are unchanged: assert_array_equal(group.atoms.positions, orig_pos) # now, do the unwrapping inplace: @@ -139,7 +143,9 @@ def test_unwrap_partial_frags(self, compound, reference, is_triclinic): # first, do the unwrapping out-of-place: group.unwrap(compound=compound, reference=reference, inplace=True) # check for correct result: - assert_almost_equal(group.positions, ref_unwrapped_pos, decimal=self.precision) + assert_almost_equal( + group.positions, ref_unwrapped_pos, decimal=self.precision + ) # make sure the position of molecule 12's last atom is unchanged: assert_array_equal(u.atoms[46].position, orig_pos) @@ -149,7 +155,9 @@ def test_unwrap_partial_frags(self, compound, reference, is_triclinic): ) @pytest.mark.parametrize("reference", ("com", "cog", None)) @pytest.mark.parametrize("is_triclinic", (False, True)) - def test_unwrap_empty_group(self, level, compound, reference, is_triclinic): + def test_unwrap_empty_group( + self, level, compound, reference, is_triclinic + ): # get a pristine test universe: u = UnWrapUniverse(is_triclinic=is_triclinic) if level == "atoms": @@ -160,7 +168,9 @@ def test_unwrap_empty_group(self, level, compound, reference, is_triclinic): group = mda.SegmentGroup([], u) group.unwrap(compound=compound, reference=reference, inplace=True) # check for correct (empty) result: - assert_array_equal(group.atoms.positions, np.empty((0, 3), dtype=np.float32)) + assert_array_equal( + group.atoms.positions, np.empty((0, 3), dtype=np.float32) + ) @pytest.mark.parametrize("level", ("atoms", "residues", "segments")) @pytest.mark.parametrize( @@ -340,7 +350,9 @@ def test_unwrap_no_masses_exception_safety(self, level, compound): "compound", ("fragments", "molecules", "residues", "group", "segments") ) @pytest.mark.parametrize("reference", ("com", "cog", None)) - def test_unwrap_no_bonds_exception_safety(self, level, compound, reference): + def test_unwrap_no_bonds_exception_safety( + self, level, compound, reference + ): # universe without bonds: u = UnWrapUniverse(have_bonds=False) # select group appropriate for compound: @@ -382,7 +394,9 @@ def test_unwrap_no_molnums_exception_safety(self, level, reference): # store original positions: orig_pos = group.atoms.positions with pytest.raises(NoDataError): - group.unwrap(compound="molecules", reference=reference, inplace=True) + group.unwrap( + compound="molecules", reference=reference, inplace=True + ) assert_array_equal(group.atoms.positions, orig_pos) @@ -407,4 +421,6 @@ def test_uncontiguous(): ) # Ok, let's make it whole again and check that we're good u.atoms.unwrap() - assert_almost_equal(ref_pos, ag.positions + displacement_vec, decimal=precision) + assert_almost_equal( + ref_pos, ag.positions + displacement_vec, decimal=precision + ) diff --git a/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py b/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py index 3d4ace4cba..fc41670a6e 100644 --- a/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py +++ b/testsuite/MDAnalysisTests/core/test_updating_atomgroup.py @@ -44,7 +44,9 @@ def ag(self, u): @pytest.fixture() def ag_updating(self, u): - return u.select_atoms("prop x < 5 and prop y < 5 and prop z < 5", updating=True) + return u.select_atoms( + "prop x < 5 and prop y < 5 and prop z < 5", updating=True + ) @pytest.fixture() def ag_updating_compounded(self, u, ag): @@ -52,7 +54,9 @@ def ag_updating_compounded(self, u, ag): @pytest.fixture() def ag_updating_chained(self, u, ag_updating): - return u.select_atoms("around 2 group sele", sele=ag_updating, updating=True) + return u.select_atoms( + "around 2 group sele", sele=ag_updating, updating=True + ) @pytest.fixture() def ag_updating_chained2(self, ag_updating): @@ -87,7 +91,9 @@ def test_update(self, u, ag, ag_updating): assert ag_updating._lastupdate is None def test_compounded_update(self, u, ag_updating_compounded): - target_idxs0 = np.array([3650, 7406, 22703, 31426, 40357, 40360, 41414]) + target_idxs0 = np.array( + [3650, 7406, 22703, 31426, 40357, 40360, 41414] + ) target_idxs1 = np.array( [3650, 8146, 23469, 23472, 31426, 31689, 31692, 34326, 41414] ) @@ -95,9 +101,13 @@ def test_compounded_update(self, u, ag_updating_compounded): next(u.trajectory) assert_equal(ag_updating_compounded.indices, target_idxs1) - def test_chained_update(self, u, ag_updating_chained, ag_updating_compounded): + def test_chained_update( + self, u, ag_updating_chained, ag_updating_compounded + ): target_idxs = np.array([4471, 7406, 11973, 11975, 34662, 44042]) - assert_equal(ag_updating_chained.indices, ag_updating_compounded.indices) + assert_equal( + ag_updating_chained.indices, ag_updating_compounded.indices + ) next(u.trajectory) assert_equal(ag_updating_chained.indices, target_idxs) @@ -285,7 +295,9 @@ def test_representations(): rep = repr(ag_updating) assert "1 atom," in rep - ag_updating = u.atoms[:-1].select_atoms("bynum 1", "bynum 2", updating=True) + ag_updating = u.atoms[:-1].select_atoms( + "bynum 1", "bynum 2", updating=True + ) rep = repr(ag_updating) assert "2 atoms," in rep assert "selections 'bynum 1' + 'bynum 2'" in rep diff --git a/testsuite/MDAnalysisTests/core/test_wrap.py b/testsuite/MDAnalysisTests/core/test_wrap.py index a6e67fb0e2..76b0263a8e 100644 --- a/testsuite/MDAnalysisTests/core/test_wrap.py +++ b/testsuite/MDAnalysisTests/core/test_wrap.py @@ -58,13 +58,19 @@ def test_wrap_pass(self, level, compound, center, is_triclinic): # get the expected result: ref_wrapped_pos = u.wrapped_coords(compound, center) # first, do the wrapping out-of-place: - wrapped_pos = group.wrap(compound=compound, center=center, inplace=False) + wrapped_pos = group.wrap( + compound=compound, center=center, inplace=False + ) # check for correct result: - assert_almost_equal(wrapped_pos, ref_wrapped_pos, decimal=self.precision) + assert_almost_equal( + wrapped_pos, ref_wrapped_pos, decimal=self.precision + ) # make sure atom positions are unchanged: assert_array_equal(group.atoms.positions, orig_pos) # now, do the wrapping inplace: - wrapped_pos2 = group.wrap(compound=compound, center=center, inplace=True) + wrapped_pos2 = group.wrap( + compound=compound, center=center, inplace=True + ) # check that result is the same as for out-of-place computation: assert_array_equal(wrapped_pos, wrapped_pos2) # check that wrapped positions are applied: @@ -77,7 +83,9 @@ def test_wrap_pass(self, level, compound, center, is_triclinic): compos = group.atoms.center_of_mass(wrap=False, compound=compound) assert_in_box(compos, group.dimensions) else: - cogpos = group.atoms.center_of_geometry(wrap=False, compound=compound) + cogpos = group.atoms.center_of_geometry( + wrap=False, compound=compound + ) assert_in_box(cogpos, group.dimensions) @pytest.mark.parametrize("level", ("atoms", "residues", "segments")) @@ -118,7 +126,9 @@ def test_unwrap_wrap_cycle(self, level, compound, center, is_triclinic): ) @pytest.mark.parametrize("center", ("com", "cog")) @pytest.mark.parametrize("is_triclinic", (False, True)) - def test_wrap_partial_compound(self, level, compound, center, is_triclinic): + def test_wrap_partial_compound( + self, level, compound, center, is_triclinic + ): # get a pristine test universe: u = UnWrapUniverse(is_triclinic=is_triclinic) group = u.atoms @@ -173,7 +183,9 @@ def test_wrap_empty_group(self, level, compound, center, is_triclinic): group = group.segments group.wrap(compound=compound, center=center, inplace=True) # check for correct (empty) result: - assert_array_equal(group.atoms.positions, np.empty((0, 3), dtype=np.float32)) + assert_array_equal( + group.atoms.positions, np.empty((0, 3), dtype=np.float32) + ) @pytest.mark.parametrize("level", ("atoms", "residues", "segments")) @pytest.mark.parametrize( @@ -232,13 +244,19 @@ def test_wrap_com_cog_difference(self, compound, is_triclinic): # the first unit cell in negative x-direction. group.masses = [100.0, 1.0, 1.0] # wrap with center='cog': - wrapped_pos_cog = group.wrap(compound=compound, center="cog", inplace=False) + wrapped_pos_cog = group.wrap( + compound=compound, center="cog", inplace=False + ) # get expected result: ref_wrapped_pos = u.wrapped_coords(compound, "cog")[6:9] # check for correctness: - assert_almost_equal(wrapped_pos_cog, ref_wrapped_pos, decimal=self.precision) + assert_almost_equal( + wrapped_pos_cog, ref_wrapped_pos, decimal=self.precision + ) # wrap with center='com': - wrapped_pos_com = group.wrap(compound=compound, center="com", inplace=False) + wrapped_pos_com = group.wrap( + compound=compound, center="com", inplace=False + ) # assert that the com result is shifted with respect to the cog result # by one box length in the x-direction: shift = np.array([10.0, 0.0, 0.0], dtype=np.float32) diff --git a/testsuite/MDAnalysisTests/core/util.py b/testsuite/MDAnalysisTests/core/util.py index 4cbe3d20ca..52b83d64d6 100644 --- a/testsuite/MDAnalysisTests/core/util.py +++ b/testsuite/MDAnalysisTests/core/util.py @@ -376,7 +376,9 @@ def unwrapped_coords(self, compound, reference): if reference is not None: ref = reference.lower() if ref not in ["com", "cog"]: - raise ValueError("Unknown unwrap reference: {}" "".format(reference)) + raise ValueError( + "Unknown unwrap reference: {}" "".format(reference) + ) comp = compound.lower() if comp not in [ "group", diff --git a/testsuite/MDAnalysisTests/datafiles.py b/testsuite/MDAnalysisTests/datafiles.py index 2a4da72977..e32807058f 100644 --- a/testsuite/MDAnalysisTests/datafiles.py +++ b/testsuite/MDAnalysisTests/datafiles.py @@ -389,7 +389,7 @@ "SURFACE_PDB", # 111 FCC lattice topology for NSGrid bug #2345 "SURFACE_TRR", # full precision coordinates for NSGrid bug #2345 "DSSP", # DSSP test suite - "LAMMPSDUMP_non_linear", + "LAMMPSDUMP_non_linear" ] from importlib import resources @@ -397,7 +397,9 @@ _data_ref = resources.files("MDAnalysisTests.data") -WIN_PDB_multiframe = (_data_ref / "windows/WIN_nmr_neopetrosiamide.pdb").as_posix() +WIN_PDB_multiframe = ( + _data_ref / "windows/WIN_nmr_neopetrosiamide.pdb" +).as_posix() WIN_DLP_HISTORY = (_data_ref / "windows/WIN_HISTORY").as_posix() WIN_TRJ = (_data_ref / "windows/WIN_ache.mdcrd").as_posix() WIN_ARC = (_data_ref / "windows/WIN_test.arc").as_posix() @@ -446,7 +448,9 @@ PSF_NAMD = (_data_ref / "namd_cgenff.psf").as_posix() PDB_NAMD = (_data_ref / "namd_cgenff.pdb").as_posix() -PDB_multipole = (_data_ref / "water_methane_acetic-acid_ammonia.pdb").as_posix() +PDB_multipole = ( + _data_ref / "water_methane_acetic-acid_ammonia.pdb" +).as_posix() PSF_NAMD_TRICLINIC = (_data_ref / "SiN_tric_namd.psf").as_posix() DCD_NAMD_TRICLINIC = (_data_ref / "SiN_tric_namd.dcd").as_posix() PSF_NAMD_GBIS = (_data_ref / "adk_closed_NAMD.psf").as_posix() @@ -474,7 +478,9 @@ PDB_mc_gz = (_data_ref / "model_then_cryst.pdb.gz").as_posix() PDB_mc_bz2 = (_data_ref / "model_then_cryst.pdb.bz2").as_posix() PDB_chainidnewres = (_data_ref / "chainIDnewres.pdb.gz").as_posix() -PDB_sameresid_diffresname = (_data_ref / "sameresid_diffresname.pdb").as_posix() +PDB_sameresid_diffresname = ( + _data_ref / "sameresid_diffresname.pdb" +).as_posix() PDB_chainidrepeat = (_data_ref / "chainIDrepeat.pdb.gz").as_posix() PDB_multiframe = (_data_ref / "nmr_neopetrosiamide.pdb").as_posix() PDB_helix = (_data_ref / "A6PA6_alpha.pdb").as_posix() @@ -492,7 +498,9 @@ GRO_large = (_data_ref / "bigbox.gro.bz2").as_posix() GRO_residwrap = (_data_ref / "residwrap.gro").as_posix() GRO_residwrap_0base = (_data_ref / "residwrap_0base.gro").as_posix() -GRO_sameresid_diffresname = (_data_ref / "sameresid_diffresname.gro").as_posix() +GRO_sameresid_diffresname = ( + _data_ref / "sameresid_diffresname.gro" +).as_posix() PDB = (_data_ref / "adk_oplsaa.pdb").as_posix() XTC = (_data_ref / "adk_oplsaa.xtc").as_posix() TRR = (_data_ref / "adk_oplsaa.trr").as_posix() @@ -504,12 +512,20 @@ PDB_xlserial = (_data_ref / "xl_serial.pdb").as_posix() GRO_MEMPROT = (_data_ref / "analysis/YiiP_lipids.gro.gz").as_posix() XTC_MEMPROT = (_data_ref / "analysis/YiiP_lipids.xtc").as_posix() -XTC_multi_frame = (_data_ref / "xtc_test_only_10_frame_10_atoms.xtc").as_posix() -TRR_multi_frame = (_data_ref / "trr_test_only_10_frame_10_atoms.trr").as_posix() +XTC_multi_frame = ( + _data_ref / "xtc_test_only_10_frame_10_atoms.xtc" +).as_posix() +TRR_multi_frame = ( + _data_ref / "trr_test_only_10_frame_10_atoms.trr" +).as_posix() TNG_traj = (_data_ref / "argon_npt_compressed.tng").as_posix() TNG_traj_gro = (_data_ref / "argon_npt_compressed.gro.gz").as_posix() -TNG_traj_uneven_blocks = (_data_ref / "argon_npt_compressed_uneven.tng").as_posix() -TNG_traj_vels_forces = (_data_ref / "argon_npt_compressed_vels_forces.tng").as_posix() +TNG_traj_uneven_blocks = ( + _data_ref / "argon_npt_compressed_uneven.tng" +).as_posix() +TNG_traj_vels_forces = ( + _data_ref / "argon_npt_compressed_vels_forces.tng" +).as_posix() PDB_xvf = (_data_ref / "cobrotoxin.pdb").as_posix() TPR_xvf = (_data_ref / "cobrotoxin.tpr").as_posix() TRR_xvf = (_data_ref / "cobrotoxin.trr").as_posix() @@ -559,13 +575,23 @@ TPR510_bonded = (_data_ref / "tprs/all_bonded/dummy_5.1.tpr").as_posix() TPR2016_bonded = (_data_ref / "tprs/all_bonded/dummy_2016.tpr").as_posix() TPR2018_bonded = (_data_ref / "tprs/all_bonded/dummy_2018.tpr").as_posix() -TPR2019B3_bonded = (_data_ref / "tprs/all_bonded/dummy_2019-beta3.tpr").as_posix() -TPR2020B2_bonded = (_data_ref / "tprs/all_bonded/dummy_2020-beta2.tpr").as_posix() +TPR2019B3_bonded = ( + _data_ref / "tprs/all_bonded/dummy_2019-beta3.tpr" +).as_posix() +TPR2020B2_bonded = ( + _data_ref / "tprs/all_bonded/dummy_2020-beta2.tpr" +).as_posix() TPR2020_bonded = (_data_ref / "tprs/all_bonded/dummy_2020.tpr").as_posix() -TPR2020_double_bonded = (_data_ref / "tprs/all_bonded/dummy_2020_double.tpr").as_posix() +TPR2020_double_bonded = ( + _data_ref / "tprs/all_bonded/dummy_2020_double.tpr" +).as_posix() TPR2021_bonded = (_data_ref / "tprs/all_bonded/dummy_2021.tpr").as_posix() -TPR2021_double_bonded = (_data_ref / "tprs/all_bonded/dummy_2021_double.tpr").as_posix() -TPR2022RC1_bonded = (_data_ref / "tprs/all_bonded/dummy_2022-rc1.tpr").as_posix() +TPR2021_double_bonded = ( + _data_ref / "tprs/all_bonded/dummy_2021_double.tpr" +).as_posix() +TPR2022RC1_bonded = ( + _data_ref / "tprs/all_bonded/dummy_2022-rc1.tpr" +).as_posix() TPR2023_bonded = (_data_ref / "tprs/all_bonded/dummy_2023.tpr").as_posix() TPR2024_bonded = (_data_ref / "tprs/all_bonded/dummy_2024.tpr").as_posix() TPR2024_4_bonded = (_data_ref / "tprs/all_bonded/dummy_2024_4.tpr").as_posix() @@ -698,7 +724,9 @@ mol2_molecule = (_data_ref / "mol2/Molecule.mol2").as_posix() mol2_ligand = (_data_ref / "mol2/Ligand.mol2").as_posix() mol2_broken_molecule = (_data_ref / "mol2/BrokenMolecule.mol2").as_posix() -mol2_comments_header = (_data_ref / "mol2/Molecule_comments_header.mol2").as_posix() +mol2_comments_header = ( + _data_ref / "mol2/Molecule_comments_header.mol2" +).as_posix() # MOL2 file without substructure field mol2_zinc = (_data_ref / "mol2/zinc_856218.mol2").as_posix() # MOL2 file without bonds @@ -709,8 +737,12 @@ capping_ace = (_data_ref / "capping/ace.pdb").as_posix() capping_nma = (_data_ref / "capping/nma.pdb").as_posix() -contacts_villin_folded = (_data_ref / "contacts/villin_folded.gro.bz2").as_posix() -contacts_villin_unfolded = (_data_ref / "contacts/villin_unfolded.gro.bz2").as_posix() +contacts_villin_folded = ( + _data_ref / "contacts/villin_folded.gro.bz2" +).as_posix() +contacts_villin_unfolded = ( + _data_ref / "contacts/villin_unfolded.gro.bz2" +).as_posix() contacts_file = (_data_ref / "contacts/2F4K_qlist5_remap.dat").as_posix() trz4data = (_data_ref / "lammps/datatest.trz").as_posix() @@ -728,16 +760,24 @@ LAMMPSDUMP = (_data_ref / "lammps/wat.lammpstrj.bz2").as_posix() LAMMPSDUMP_long = (_data_ref / "lammps/wat.lammpstrj_long.bz2").as_posix() LAMMPSDUMP_allinfo = (_data_ref / "lammps/mass_q_elem.lammpstrj").as_posix() -LAMMPSDUMP_nomass_elemx = (_data_ref / "lammps/nomass_elemx.lammpstrj").as_posix() -LAMMPSDUMP_allcoords = (_data_ref / "lammps/spce_all_coords.lammpstrj.bz2").as_posix() -LAMMPSDUMP_nocoords = (_data_ref / "lammps/spce_no_coords.lammpstrj.bz2").as_posix() +LAMMPSDUMP_nomass_elemx = ( + _data_ref / "lammps/nomass_elemx.lammpstrj" +).as_posix() +LAMMPSDUMP_allcoords = ( + _data_ref / "lammps/spce_all_coords.lammpstrj.bz2" +).as_posix() +LAMMPSDUMP_nocoords = ( + _data_ref / "lammps/spce_no_coords.lammpstrj.bz2" +).as_posix() LAMMPSDUMP_triclinic = (_data_ref / "lammps/albite_triclinic.dump").as_posix() LAMMPSDUMP_image_vf = (_data_ref / "lammps/image_vf.lammpstrj").as_posix() LAMMPS_image_vf = (_data_ref / "lammps/image_vf.data").as_posix() LAMMPSDUMP_chain1 = (_data_ref / "lammps/chain_dump_1.lammpstrj").as_posix() LAMMPSDUMP_chain2 = (_data_ref / "lammps/chain_dump_2.lammpstrj").as_posix() LAMMPS_chain = (_data_ref / "lammps/chain_initial.data").as_posix() -LAMMPSdata_many_bonds = (_data_ref / "lammps/a_lot_of_bond_types.data").as_posix() +LAMMPSdata_many_bonds = ( + _data_ref / "lammps/a_lot_of_bond_types.data" +).as_posix() LAMMPSdata_additional_columns = ( _data_ref / "lammps/additional_columns.data" ).as_posix() @@ -752,7 +792,9 @@ GMS_ASYMSURF = (_data_ref / "gms/surf2wat.gms").as_posix() two_water_gro = (_data_ref / "two_water_gro.gro").as_posix() -two_water_gro_multiframe = (_data_ref / "two_water_gro_multiframe.gro").as_posix() +two_water_gro_multiframe = ( + _data_ref / "two_water_gro_multiframe.gro" +).as_posix() two_water_gro_nonames = (_data_ref / "two_water_gro_nonames.gro").as_posix() two_water_gro_widebox = (_data_ref / "two_water_gro_widebox.gro").as_posix() @@ -762,7 +804,9 @@ DLP_HISTORY = (_data_ref / "dlpoly/HISTORY").as_posix() DLP_HISTORY_order = (_data_ref / "dlpoly/HISTORY_order").as_posix() DLP_HISTORY_minimal = (_data_ref / "dlpoly/HISTORY_minimal").as_posix() -DLP_HISTORY_minimal_cell = (_data_ref / "dlpoly/HISTORY_minimal_cell").as_posix() +DLP_HISTORY_minimal_cell = ( + _data_ref / "dlpoly/HISTORY_minimal_cell" +).as_posix() DLP_HISTORY_classic = (_data_ref / "dlpoly/HISTORY_classic").as_posix() waterPSF = (_data_ref / "watdyn.psf").as_posix() @@ -811,11 +855,21 @@ TRC_TRAJ2_VAC = (_data_ref / "gromos11/gromos11_traj_vac_2.trc.gz").as_posix() TRC_PDB_SOLV = (_data_ref / "gromos11/gromos11_traj_solv.pdb.gz").as_posix() TRC_TRAJ_SOLV = (_data_ref / "gromos11/gromos11_traj_solv.trc.gz").as_posix() -TRC_CLUSTER_VAC = (_data_ref / "gromos11/gromos11_cluster_vac.trj.gz").as_posix() -TRC_TRICLINIC_SOLV = (_data_ref / "gromos11/gromos11_triclinic_solv.trc.gz").as_posix() -TRC_TRUNCOCT_VAC = (_data_ref / "gromos11/gromos11_truncOcta_vac.trc.gz").as_posix() -TRC_GENBOX_ORIGIN = (_data_ref / "gromos11/gromos11_genbox_origin.trc.gz").as_posix() -TRC_GENBOX_EULER = (_data_ref / "gromos11/gromos11_genbox_euler.trc.gz").as_posix() +TRC_CLUSTER_VAC = ( + _data_ref / "gromos11/gromos11_cluster_vac.trj.gz" +).as_posix() +TRC_TRICLINIC_SOLV = ( + _data_ref / "gromos11/gromos11_triclinic_solv.trc.gz" +).as_posix() +TRC_TRUNCOCT_VAC = ( + _data_ref / "gromos11/gromos11_truncOcta_vac.trc.gz" +).as_posix() +TRC_GENBOX_ORIGIN = ( + _data_ref / "gromos11/gromos11_genbox_origin.trc.gz" +).as_posix() +TRC_GENBOX_EULER = ( + _data_ref / "gromos11/gromos11_genbox_euler.trc.gz" +).as_posix() TRC_EMPTY = (_data_ref / "gromos11/gromos11_empty.trc").as_posix() DihedralArray = (_data_ref / "adk_oplsaa_dihedral.npy").as_posix() @@ -853,9 +907,7 @@ SURFACE_PDB = (_data_ref / "surface.pdb.bz2").as_posix() SURFACE_TRR = (_data_ref / "surface.trr").as_posix() -LAMMPSDUMP_non_linear = ( - _data_ref / "custom_non_linear/test_non_linear.dump" -).as_posix() +LAMMPSDUMP_non_linear = (_data_ref / "custom_non_linear/test_non_linear.dump").as_posix() # DSSP testing: from https://github.com/ShintaroMinami/PyDSSP DSSP = (_data_ref / "dssp").as_posix() diff --git a/testsuite/MDAnalysisTests/dummy.py b/testsuite/MDAnalysisTests/dummy.py index 860ac0b8f6..7bfa11fdb8 100644 --- a/testsuite/MDAnalysisTests/dummy.py +++ b/testsuite/MDAnalysisTests/dummy.py @@ -83,7 +83,9 @@ def make_Universe( n_residues=n_residues, n_segments=n_segments, atom_resindex=np.repeat(np.arange(n_residues), n_atoms // n_residues), - residue_segindex=np.repeat(np.arange(n_segments), n_residues // n_segments), + residue_segindex=np.repeat( + np.arange(n_segments), n_residues // n_segments + ), # trajectory things trajectory=trajectory, velocities=velocities, @@ -152,7 +154,9 @@ def make_types(size): """Atoms are given types TypeA -> TypeE on a loop""" na, nr, ns = size types = itertools.cycle(string.ascii_uppercase[:5]) - return np.array(["Type{}".format(next(types)) for _ in range(na)], dtype=object) + return np.array( + ["Type{}".format(next(types)) for _ in range(na)], dtype=object + ) def make_names(size): diff --git a/testsuite/MDAnalysisTests/formats/test_libdcd.py b/testsuite/MDAnalysisTests/formats/test_libdcd.py index fd47b443d7..63a9d83622 100644 --- a/testsuite/MDAnalysisTests/formats/test_libdcd.py +++ b/testsuite/MDAnalysisTests/formats/test_libdcd.py @@ -397,13 +397,16 @@ def write_dcd(in_name, out_name, remarks="testing", header=None): @pytest.mark.xfail( - (os.name == "nt" and sys.maxsize <= 2**32) or platform.machine() == "aarch64", + (os.name == "nt" and sys.maxsize <= 2**32) + or platform.machine() == "aarch64", reason="occasional fail on 32-bit windows and ARM", ) # occasionally fails due to unreliable test timings @hypothesis.settings(deadline=None) # see Issue 3096 @given( - remarks=strategies.text(alphabet=string.printable, min_size=0, max_size=239) + remarks=strategies.text( + alphabet=string.printable, min_size=0, max_size=239 + ) ) # handle the printable ASCII strings @example(remarks="") def test_written_remarks_property(remarks, tmpdir_factory): @@ -644,7 +647,9 @@ def test_readframes_order(order, shape, dcd): assert x.shape == shape -@pytest.mark.parametrize("indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]]) +@pytest.mark.parametrize( + "indices", [[1, 2, 3, 4], [5, 10, 15, 19], [9, 4, 2, 0, 50]] +) def test_readframes_atomindices(indices, dcd): allframes = dcd.readframes(order="afc").xyz frames = dcd.readframes(indices=indices, order="afc") diff --git a/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py b/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py index 23eb6536d3..64748e3088 100644 --- a/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py +++ b/testsuite/MDAnalysisTests/formats/test_libmdaxdr.py @@ -497,7 +497,9 @@ def test_write_trr_dtype(tmpdir, dtype, trr): v = frame.v.astype(dtype) f = frame.f.astype(dtype) box = frame.box.astype(dtype) - fout.write(x, v, f, box, frame.step, frame.time, frame.lmbda, natoms) + fout.write( + x, v, f, box, frame.step, frame.time, frame.lmbda, natoms + ) @pytest.mark.parametrize("array_like", (np.array, list)) @@ -510,7 +512,9 @@ def test_write_trr_array_like(tmpdir, array_like, trr): v = array_like(frame.v) f = array_like(frame.f) box = array_like(frame.box) - fout.write(x, v, f, box, frame.step, frame.time, frame.lmbda, natoms) + fout.write( + x, v, f, box, frame.step, frame.time, frame.lmbda, natoms + ) def test_write_different_box_trr(tmpdir, trr): diff --git a/testsuite/MDAnalysisTests/guesser/test_base.py b/testsuite/MDAnalysisTests/guesser/test_base.py index b22246d99d..e890ca9957 100644 --- a/testsuite/MDAnalysisTests/guesser/test_base.py +++ b/testsuite/MDAnalysisTests/guesser/test_base.py @@ -58,13 +58,16 @@ class TestGuesser1(GuesserBase): def test_guess_invalid_attribute(self): with pytest.raises( ValueError, - match="default guesser can not guess " "the following attribute: foo", + match="default guesser can not guess " + "the following attribute: foo", ): mda.Universe(datafiles.PDB_xsmall, to_guess=["foo"]) def test_guess_attribute_with_missing_parent_attr(self): names = Atomnames(np.array(["C", "HB", "HA", "O"], dtype=object)) - masses = Masses(np.array([np.nan, np.nan, np.nan, np.nan], dtype=np.float64)) + masses = Masses( + np.array([np.nan, np.nan, np.nan, np.nan], dtype=np.float64) + ) top = Topology(4, 1, 1, attrs=[names, masses]) u = mda.Universe(top, to_guess=["masses"]) assert_allclose( @@ -85,7 +88,9 @@ def test_partial_guessing(self): masses = Masses(np.array([0, np.nan, np.nan, 0], dtype=np.float64)) top = Topology(4, 1, 1, attrs=[types, masses]) u = mda.Universe(top, to_guess=["masses"]) - assert_allclose(u.atoms.masses, np.array([0, 1.00800, 1.00800, 0]), atol=0) + assert_allclose( + u.atoms.masses, np.array([0, 1.00800, 1.00800, 0]), atol=0 + ) def test_force_guess_priority(self): "check that passing the attribute to force_guess have higher power" @@ -180,7 +185,9 @@ def test_guess_topology_objects_out_of_order_guess(self): with pytest.raises(NoDataError): u.atoms.angles - u.guess_TopologyAttrs("default", to_guess=["dihedrals", "angles", "bonds"]) + u.guess_TopologyAttrs( + "default", to_guess=["dihedrals", "angles", "bonds"] + ) assert len(u.atoms.angles) == 290 assert len(u.atoms.dihedrals) == 411 @@ -242,7 +249,9 @@ def test_guess_singular(self): def test_Universe_guess_bonds_deprecated(): - with pytest.warns(DeprecationWarning, match="`guess_bonds` keyword is deprecated"): + with pytest.warns( + DeprecationWarning, match="`guess_bonds` keyword is deprecated" + ): u = mda.Universe(datafiles.PDB_xsmall, guess_bonds=True) diff --git a/testsuite/MDAnalysisTests/guesser/test_default_guesser.py b/testsuite/MDAnalysisTests/guesser/test_default_guesser.py index 9aa6c2e27e..92c24593c3 100644 --- a/testsuite/MDAnalysisTests/guesser/test_default_guesser.py +++ b/testsuite/MDAnalysisTests/guesser/test_default_guesser.py @@ -57,7 +57,9 @@ def test_guess_masses_from_universe(self): u = mda.Universe(topology) assert isinstance(u.atoms.masses, np.ndarray) - assert_allclose(u.atoms.masses, np.array([12.011, 12.011, 1.008]), atol=0) + assert_allclose( + u.atoms.masses, np.array([12.011, 12.011, 1.008]), atol=0 + ) def test_guess_masses_from_guesser_object(self, default_guesser): elements = ["H", "Ca", "Am"] @@ -88,7 +90,9 @@ def test_guess_atom_mass(self, default_guesser): def test_guess_masses_with_no_reference_elements(self): u = mda.Universe.empty(3) - with pytest.raises(NoDataError, match=("there is no reference attributes ")): + with pytest.raises( + NoDataError, match=("there is no reference attributes ") + ): u.guess_TopologyAttrs("default", ["masses"]) @@ -123,7 +127,10 @@ def test_partial_guess_elements(self, default_guesser): def test_guess_elements_from_no_data(self): top = Topology(5) - msg = "there is no reference attributes in this " "universe to guess types from" + msg = ( + "there is no reference attributes in this " + "universe to guess types from" + ) with pytest.warns(UserWarning, match=msg): mda.Universe(top, to_guess=["types"]) @@ -205,7 +212,9 @@ def test_guess_dihedrals_with_no_angles(): def test_guess_impropers_with_angles(): "Test guessing impropers for atoms with angles" "and bonds information " - u = mda.Universe(datafiles.two_water_gro, to_guess=["bonds", "angles", "impropers"]) + u = mda.Universe( + datafiles.two_water_gro, to_guess=["bonds", "angles", "impropers"] + ) u.guess_TopologyAttrs(to_guess=["impropers"]) assert hasattr(u, "impropers") assert hasattr(u, "angles") @@ -236,12 +245,16 @@ def bond_sort(arr): def test_guess_bonds_water(): u = mda.Universe(datafiles.two_water_gro) bonds = bond_sort( - DefaultGuesser(None, box=u.dimensions).guess_bonds(u.atoms, u.atoms.positions) + DefaultGuesser(None, box=u.dimensions).guess_bonds( + u.atoms, u.atoms.positions + ) ) assert_equal(bonds, ((0, 1), (0, 2), (3, 4), (3, 5))) -@pytest.mark.parametrize("fudge_factor, n_bonds", [(0, 0), (0.55, 4), (200, 6)]) +@pytest.mark.parametrize( + "fudge_factor, n_bonds", [(0, 0), (0.55, 4), (200, 6)] +) def test_guess_bonds_water_fudge_factor_passed(fudge_factor, n_bonds): u = mda.Universe( datafiles.two_water_gro, @@ -317,6 +330,8 @@ def test_guess_gasteiger_charges(smi): @requires_rdkit def test_aromaticity(): - u = mda.Universe(datafiles.PDB_small, to_guess=["elements", "aromaticities"]) + u = mda.Universe( + datafiles.PDB_small, to_guess=["elements", "aromaticities"] + ) c_aromatic = u.select_atoms("resname PHE and name CD1") assert_equal(c_aromatic.aromaticities[0], True) diff --git a/testsuite/MDAnalysisTests/lib/test_cutil.py b/testsuite/MDAnalysisTests/lib/test_cutil.py index d583551881..47c4d7f905 100644 --- a/testsuite/MDAnalysisTests/lib/test_cutil.py +++ b/testsuite/MDAnalysisTests/lib/test_cutil.py @@ -99,5 +99,7 @@ def test_in2d(): ], ) def test_in2d_VE(arr1, arr2): - with pytest.raises(ValueError, match=r"Both arrays must be \(n, 2\) arrays"): + with pytest.raises( + ValueError, match=r"Both arrays must be \(n, 2\) arrays" + ): _in2d(arr1, arr2) diff --git a/testsuite/MDAnalysisTests/lib/test_distances.py b/testsuite/MDAnalysisTests/lib/test_distances.py index 6d93ff3fbe..06abe0a99c 100644 --- a/testsuite/MDAnalysisTests/lib/test_distances.py +++ b/testsuite/MDAnalysisTests/lib/test_distances.py @@ -63,7 +63,9 @@ def test_check_result_array_wrong_dtype(self): wrong_dtype = np.int64 ref_wrong_dtype = self.ref.astype(wrong_dtype) with pytest.raises(TypeError) as err: - res = distances._check_result_array(ref_wrong_dtype, self.ref.shape) + res = distances._check_result_array( + ref_wrong_dtype, self.ref.shape + ) assert err.msg == ( "Result array must be of type numpy.float64, " "got {}.".format(wrong_dtype) @@ -124,7 +126,9 @@ def test_capped_distance_noresults(self): point1 = np.array([0.1, 0.1, 0.1], dtype=np.float32) point2 = np.array([0.95, 0.1, 0.1], dtype=np.float32) - pairs, dists = distances.capped_distance(point1, point2, max_cutoff=0.2) + pairs, dists = distances.capped_distance( + point1, point2, max_cutoff=0.2 + ) assert_equal(len(pairs), 0) @@ -307,9 +311,9 @@ def test_self_capped_distance( ) def test_method_selfselection(self, box, npoints, cutoff, meth): np.random.seed(90003) - points = (np.random.uniform(low=0, high=1.0, size=(npoints, 3))).astype( - np.float32 - ) + points = ( + np.random.uniform(low=0, high=1.0, size=(npoints, 3)) + ).astype(np.float32) method = distances._determine_method_self(points, cutoff, box=box) assert_equal(method.__name__, meth) @@ -404,7 +408,9 @@ def test_noPBC(self, backend, ref_system, pos, request): # cycle through combinations of numpy array and AtomGroup @pytest.mark.parametrize("pos0", ["ref_system", "ref_system_universe"]) @pytest.mark.parametrize("pos1", ["ref_system", "ref_system_universe"]) - def test_noPBC_mixed_combinations(self, backend, ref_system, pos0, pos1, request): + def test_noPBC_mixed_combinations( + self, backend, ref_system, pos0, pos1, request + ): _, points, reference, _ = ref_system # reference values _, _, ref_val, _ = request.getfixturevalue(pos0) _, points_val, _, _ = request.getfixturevalue(pos1) @@ -439,11 +445,15 @@ def test_PBC(self, backend, ref_system, pos, request): # cycle through combinations of numpy array and AtomGroup @pytest.mark.parametrize("pos0", ["ref_system", "ref_system_universe"]) @pytest.mark.parametrize("pos1", ["ref_system", "ref_system_universe"]) - def test_PBC_mixed_combinations(self, backend, ref_system, pos0, pos1, request): + def test_PBC_mixed_combinations( + self, backend, ref_system, pos0, pos1, request + ): box, points, _, _ = ref_system _, _, ref_val, _ = request.getfixturevalue(pos0) _, points_val, _, _ = request.getfixturevalue(pos1) - d = distances.distance_array(ref_val, points_val, box=box, backend=backend) + d = distances.distance_array( + ref_val, points_val, box=box, backend=backend + ) assert_almost_equal( d, np.array([[0.0, 0.0, 0.0, self._dist(points[3], ref=[1, 1, 2])]]), @@ -532,7 +542,9 @@ def test_simple(self, DCD_Universe, backend): trajectory[10] x1 = U.atoms.positions d = distances.distance_array(x0, x1, backend=backend) - assert_equal(d.shape, (3341, 3341), "wrong shape (should be" "(Natoms,Natoms))") + assert_equal( + d.shape, (3341, 3341), "wrong shape (should be" "(Natoms,Natoms))" + ) assert_almost_equal( d.min(), 0.11981228170520701, @@ -582,7 +594,9 @@ def test_periodic(self, DCD_Universe, backend): x0 = U.atoms.positions trajectory[10] x1 = U.atoms.positions - d = distances.distance_array(x0, x1, box=U.coord.dimensions, backend=backend) + d = distances.distance_array( + x0, x1, box=U.coord.dimensions, backend=backend + ) assert_equal( d.shape, (3341, 3341), @@ -639,14 +653,18 @@ def test_atomgroup_simple(self, DCD_Universe, DCD_Universe2, backend): ("index 9", np.s_[8, :]), ], ) - def test_atomgroup_matches_numpy(self, DCD_Universe, backend, sel, np_slice, box): + def test_atomgroup_matches_numpy( + self, DCD_Universe, backend, sel, np_slice, box + ): U = DCD_Universe x0_ag = U.select_atoms(sel) x0_arr = U.atoms.positions[np_slice] x1_ag = U.select_atoms(sel) x1_arr = U.atoms.positions[np_slice] d_ag = distances.distance_array(x0_ag, x1_ag, box=box, backend=backend) - d_arr = distances.distance_array(x0_arr, x1_arr, box=box, backend=backend) + d_arr = distances.distance_array( + x0_arr, x1_arr, box=box, backend=backend + ) assert_allclose( d_ag, d_arr, err_msg="AtomGroup and NumPy distances do not match" ) @@ -690,7 +708,9 @@ def test_simple(self, DCD_Universe, backend): x0 = U.atoms.positions d = distances.self_distance_array(x0, backend=backend) N = 3341 * (3341 - 1) / 2 - assert_equal(d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))") + assert_equal( + d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))" + ) assert_almost_equal( d.min(), 0.92905562402529318, @@ -713,7 +733,9 @@ def test_outarray(self, DCD_Universe, backend): N = natoms * (natoms - 1) // 2 d = np.zeros((N,), np.float64) distances.self_distance_array(x0, result=d, backend=backend) - assert_equal(d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))") + assert_equal( + d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))" + ) assert_almost_equal( d.min(), 0.92905562402529318, @@ -735,8 +757,12 @@ def test_periodic(self, DCD_Universe, backend): x0 = U.atoms.positions natoms = len(U.atoms) N = natoms * (natoms - 1) / 2 - d = distances.self_distance_array(x0, box=U.coord.dimensions, backend=backend) - assert_equal(d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))") + d = distances.self_distance_array( + x0, box=U.coord.dimensions, backend=backend + ) + assert_equal( + d.shape, (N,), "wrong shape (should be (Natoms*(Natoms-1)/2,))" + ) assert_almost_equal( d.min(), 0.92905562402529318, @@ -757,7 +783,9 @@ def test_atomgroup_simple(self, DCD_Universe, backend): x0 = U.select_atoms("all") d = distances.self_distance_array(x0, backend=backend) N = 3341 * (3341 - 1) / 2 - assert_equal(d.shape, (N,), "wrong shape (should be" " (Natoms*(Natoms-1)/2,))") + assert_equal( + d.shape, (N,), "wrong shape (should be" " (Natoms*(Natoms-1)/2,))" + ) assert_almost_equal( d.min(), 0.92905562402529318, @@ -781,7 +809,9 @@ def test_atomgroup_simple(self, DCD_Universe, backend): ("index 9", np.s_[8, :]), ], ) - def test_atomgroup_matches_numpy(self, DCD_Universe, backend, sel, np_slice, box): + def test_atomgroup_matches_numpy( + self, DCD_Universe, backend, sel, np_slice, box + ): U = DCD_Universe x0_ag = U.select_atoms(sel) @@ -906,7 +936,9 @@ def test_selfdist(self, S_mol, box, tri_vec_box, backend): # distopia backend support R_coords = distances.transform_StoR(S_mol1, box, backend="serial") # Transform functions are tested elsewhere so taken as working here - dists = distances.self_distance_array(R_coords, box=box, backend=backend) + dists = distances.self_distance_array( + R_coords, box=box, backend=backend + ) # Manually calculate self_distance_array manual = np.zeros(len(dists), dtype=np.float64) distpos = 0 @@ -932,7 +964,9 @@ def test_selfdist(self, S_mol, box, tri_vec_box, backend): # distopia backend support R_coords = distances.transform_StoR(S_mol2, box, backend="serial") # Transform functions are tested elsewhere so taken as working here - dists = distances.self_distance_array(R_coords, box=box, backend=backend) + dists = distances.self_distance_array( + R_coords, box=box, backend=backend + ) # Manually calculate self_distance_array manual = np.zeros(len(dists), dtype=np.float64) distpos = 0 @@ -962,7 +996,9 @@ def test_distarray(self, S_mol, tri_vec_box, box, backend): R_mol2 = distances.transform_StoR(S_mol2, box, backend="serial") # Try with box - dists = distances.distance_array(R_mol1, R_mol2, box=box, backend=backend) + dists = distances.distance_array( + R_mol1, R_mol2, box=box, backend=backend + ) # Manually calculate distance_array manual = np.zeros((len(R_mol1), len(R_mol2))) for i, Ri in enumerate(R_mol1): @@ -982,7 +1018,9 @@ def test_distarray(self, S_mol, tri_vec_box, box, backend): def test_pbc_dist(self, S_mol, box, backend): S_mol1, S_mol2 = S_mol results = np.array([[37.629944]]) - dists = distances.distance_array(S_mol1, S_mol2, box=box, backend=backend) + dists = distances.distance_array( + S_mol1, S_mol2, box=box, backend=backend + ) assert_almost_equal( dists, @@ -998,7 +1036,9 @@ def test_pbc_wrong_wassenaar_distance(self, backend): a, b, c = tri_vec_box point_a = a + b point_b = 0.5 * point_a - dist = distances.distance_array(point_a, point_b, box=box, backend=backend) + dist = distances.distance_array( + point_a, point_b, box=box, backend=backend + ) assert_almost_equal(dist[0, 0], 1) # check that our distance is different from the wassenaar distance as # expected. @@ -1145,7 +1185,8 @@ def positions_atomgroups(positions): a, b, c, d = positions arrs = [a, b, c, d] universes = [ - MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) for arr in arrs + MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) + for arr in arrs ] for u, a in zip(universes, arrs): u.atoms.positions = a @@ -1172,7 +1213,9 @@ def test_bonds(self, box, backend, dtype, pos, request): a, b, c, d = request.getfixturevalue(pos) a, b, c, d = convert_position_dtype_if_ndarray(a, b, c, d, dtype) dists = distances.calc_bonds(a, b, backend=backend) - assert_equal(len(dists), 4, err_msg="calc_bonds results have wrong length") + assert_equal( + len(dists), 4, err_msg="calc_bonds results have wrong length" + ) dists_pbc = distances.calc_bonds(a, b, box=box, backend=backend) # tests 0 length assert_almost_equal( @@ -1251,7 +1294,9 @@ def test_bonds_badresult(self, positions, backend): @pytest.mark.parametrize("dtype", (np.float32, np.float64)) @pytest.mark.parametrize("pos", ["positions", "positions_atomgroups"]) @pytest.mark.parametrize("backend", distopia_conditional_backend()) - def test_bonds_triclinic(self, triclinic_box, backend, dtype, pos, request): + def test_bonds_triclinic( + self, triclinic_box, backend, dtype, pos, request + ): a, b, c, d = request.getfixturevalue(pos) a, b, c, d = convert_position_dtype_if_ndarray(a, b, c, d, dtype) dists = distances.calc_bonds(a, b, box=triclinic_box, backend=backend) @@ -1277,7 +1322,9 @@ def test_bonds_single_coords(self, shift, periodic, backend): coords[1] += shift2 * box[:3] box = box if periodic else None - result = distances.calc_bonds(coords[0], coords[1], box, backend=backend) + result = distances.calc_bonds( + coords[0], coords[1], box, backend=backend + ) reference = 2.0 if periodic else np.linalg.norm(coords[0] - coords[1]) @@ -1291,7 +1338,9 @@ def test_angles(self, backend, dtype, pos, request): a, b, c, d = convert_position_dtype_if_ndarray(a, b, c, d, dtype) angles = distances.calc_angles(a, b, c, backend=backend) # Check calculated values - assert_equal(len(angles), 4, err_msg="calc_angles results have wrong length") + assert_equal( + len(angles), 4, err_msg="calc_angles results have wrong length" + ) # assert_almost_equal(angles[0], 0.0, self.prec, # err_msg="Zero length angle calculation failed") # What should this be? assert_almost_equal( @@ -1427,7 +1476,9 @@ def test_calc_dihedrals_results_inplace_all_backends( c3[:, 1] = 3 result = np.zeros(N, dtype=np.float64) - distances.calc_dihedrals(c0, c1, c2, c3, result=result, backend=backend) + distances.calc_dihedrals( + c0, c1, c2, c3, result=result, backend=backend + ) expected = np.ones(N, dtype=dtype) * 0 # test the result array is updated in place assert_almost_equal( @@ -1458,7 +1509,9 @@ def test_dihedrals_bad_result(self, positions, backend): badresult = np.zeros(len(a) - 1) # Bad result array with pytest.raises(ValueError): - distances.calc_dihedrals(a, b, c, d, result=badresult, backend=backend) + distances.calc_dihedrals( + a, b, c, d, result=badresult, backend=backend + ) @pytest.mark.parametrize( "case", @@ -1551,7 +1604,9 @@ def test_numpy_compliance_angles(self, positions, backend): angles = distances.calc_angles(a, b, c, backend=backend) vec1 = a - b vec2 = c - b - angles_numpy = np.array([mdamath.angle(x, y) for x, y in zip(vec1, vec2)]) + angles_numpy = np.array( + [mdamath.angle(x, y) for x, y in zip(vec1, vec2)] + ) # numpy 0 angle returns NaN rather than 0 assert_almost_equal( angles[1:], @@ -1622,7 +1677,9 @@ def test_ortho_PBC(self, backend, pos, request, DCD_universe_pos): with pytest.raises(ValueError): cyth1 = distances.apply_PBC(positions, box[:3], backend=backend) cyth2 = distances.apply_PBC(positions, box, backend=backend) - reference = DCD_universe_pos - np.floor(DCD_universe_pos / box[:3]) * box[:3] + reference = ( + DCD_universe_pos - np.floor(DCD_universe_pos / box[:3]) * box[:3] + ) assert_almost_equal( cyth2, @@ -1786,7 +1843,9 @@ def test_dihedrals(self, positions, backend): test2 = distances.calc_dihedrals(a, b2, c, d, box=box, backend=backend) test3 = distances.calc_dihedrals(a, b, c2, d, box=box, backend=backend) test4 = distances.calc_dihedrals(a, b, c, d2, box=box, backend=backend) - test5 = distances.calc_dihedrals(a2, b2, c2, d2, box=box, backend=backend) + test5 = distances.calc_dihedrals( + a2, b2, c2, d2, box=box, backend=backend + ) for val in [test1, test2, test3, test4, test5]: assert_almost_equal( @@ -1833,7 +1892,8 @@ def coords(): @pytest.fixture() def coords_atomgroups(coords): universes = [ - MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) for arr in coords + MDAnalysis.Universe.empty(arr.shape[0], trajectory=True) + for arr in coords ] for u, a in zip(universes, coords): u.atoms.positions = a @@ -1844,7 +1904,9 @@ def coords_atomgroups(coords): def test_input_unchanged_distance_array(self, coords, box, backend): crds = coords[:2] refs = [crd.copy() for crd in crds] - res = distances.distance_array(crds[0], crds[1], box=box, backend=backend) + res = distances.distance_array( + crds[0], crds[1], box=box, backend=backend + ) assert_equal(crds, refs) @pytest.mark.parametrize("box", boxes) @@ -1854,7 +1916,9 @@ def test_input_unchanged_distance_array_atomgroup( ): crds = coords_atomgroups[:2] refs = [crd.positions.copy() for crd in crds] - res = distances.distance_array(crds[0], crds[1], box=box, backend=backend) + res = distances.distance_array( + crds[0], crds[1], box=box, backend=backend + ) assert_equal([crd.positions for crd in crds], refs) @pytest.mark.parametrize("box", boxes) @@ -1894,7 +1958,9 @@ def test_input_unchanged_capped_distance(self, coords, box, met, backend): @pytest.mark.parametrize("box", boxes) @pytest.mark.parametrize("met", ["bruteforce", "pkdtree", "nsgrid", None]) @pytest.mark.parametrize("backend", distopia_conditional_backend()) - def test_input_unchanged_self_capped_distance(self, coords, box, met, backend): + def test_input_unchanged_self_capped_distance( + self, coords, box, met, backend + ): crd = coords[0] ref = crd.copy() r_cut = 0.25 @@ -1905,7 +1971,9 @@ def test_input_unchanged_self_capped_distance(self, coords, box, met, backend): @pytest.mark.parametrize("box", boxes[:2]) @pytest.mark.parametrize("backend", ["serial", "openmp"]) - def test_input_unchanged_transform_RtoS_and_StoR(self, coords, box, backend): + def test_input_unchanged_transform_RtoS_and_StoR( + self, coords, box, backend + ): crd = coords[0] ref = crd.copy() res = distances.transform_RtoS(crd, box, backend=backend) @@ -1938,7 +2006,9 @@ def test_input_unchanged_calc_bonds_atomgroup( def test_input_unchanged_calc_angles(self, coords, box, backend): crds = coords[:3] refs = [crd.copy() for crd in crds] - res = distances.calc_angles(crds[0], crds[1], crds[2], box=box, backend=backend) + res = distances.calc_angles( + crds[0], crds[1], crds[2], box=box, backend=backend + ) assert_equal(crds, refs) @pytest.mark.parametrize("box", boxes) @@ -1948,7 +2018,9 @@ def test_input_unchanged_calc_angles_atomgroup( ): crds = coords_atomgroups[:3] refs = [crd.positions.copy() for crd in crds] - res = distances.calc_angles(crds[0], crds[1], crds[2], box=box, backend=backend) + res = distances.calc_angles( + crds[0], crds[1], crds[2], box=box, backend=backend + ) assert_equal([crd.positions for crd in crds], refs) @pytest.mark.parametrize("box", boxes) @@ -1983,7 +2055,9 @@ def test_input_unchanged_apply_PBC(self, coords, box, backend): @pytest.mark.parametrize("box", boxes[:2]) @pytest.mark.parametrize("backend", ["serial", "openmp"]) - def test_input_unchanged_apply_PBC_atomgroup(self, coords_atomgroups, box, backend): + def test_input_unchanged_apply_PBC_atomgroup( + self, coords_atomgroups, box, backend + ): crd = coords_atomgroups[0] ref = crd.positions.copy() res = distances.apply_PBC(crd, box, backend=backend) @@ -2031,7 +2105,9 @@ def test_empty_input_distance_array(self, empty_coord, box, backend): @pytest.mark.parametrize("box", boxes) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_empty_input_self_distance_array(self, empty_coord, box, backend): - res = distances.self_distance_array(empty_coord, box=box, backend=backend) + res = distances.self_distance_array( + empty_coord, box=box, backend=backend + ) assert_equal(res, np.empty((0,), dtype=np.float64)) @pytest.mark.parametrize("box", boxes) @@ -2096,7 +2172,9 @@ def test_empty_input_transform_StoR(self, empty_coord, box, backend): @pytest.mark.parametrize("box", boxes) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_empty_input_calc_bonds(self, empty_coord, box, backend): - res = distances.calc_bonds(empty_coord, empty_coord, box=box, backend=backend) + res = distances.calc_bonds( + empty_coord, empty_coord, box=box, backend=backend + ) assert_equal(res, np.empty((0,), dtype=np.float64)) @pytest.mark.parametrize("box", boxes) @@ -2276,7 +2354,9 @@ def test_output_dtype_transform_RtoS(self, incoords, box, backend): assert res.shape == incoords.shape @pytest.mark.parametrize("box", boxes) - @pytest.mark.parametrize("incoords", [2 * [coords[0]]] + list(comb(coords[1:], 2))) + @pytest.mark.parametrize( + "incoords", [2 * [coords[0]]] + list(comb(coords[1:], 2)) + ) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_output_type_calc_bonds(self, incoords, box, backend): res = distances.calc_bonds(*incoords, box=box, backend=backend) @@ -2290,7 +2370,9 @@ def test_output_type_calc_bonds(self, incoords, box, backend): assert res.shape == (coord.shape[0],) @pytest.mark.parametrize("box", boxes) - @pytest.mark.parametrize("incoords", [3 * [coords[0]]] + list(comb(coords[1:], 3))) + @pytest.mark.parametrize( + "incoords", [3 * [coords[0]]] + list(comb(coords[1:], 3)) + ) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_output_type_calc_angles(self, incoords, box, backend): res = distances.calc_angles(*incoords, box=box, backend=backend) @@ -2304,7 +2386,9 @@ def test_output_type_calc_angles(self, incoords, box, backend): assert res.shape == (coord.shape[0],) @pytest.mark.parametrize("box", boxes) - @pytest.mark.parametrize("incoords", [4 * [coords[0]]] + list(comb(coords[1:], 4))) + @pytest.mark.parametrize( + "incoords", [4 * [coords[0]]] + list(comb(coords[1:], 4)) + ) @pytest.mark.parametrize("backend", distopia_conditional_backend()) def test_output_type_calc_dihedrals(self, incoords, box, backend): res = distances.calc_dihedrals(*incoords, box=box, backend=backend) diff --git a/testsuite/MDAnalysisTests/lib/test_neighborsearch.py b/testsuite/MDAnalysisTests/lib/test_neighborsearch.py index 50a118ef7d..29a179350d 100644 --- a/testsuite/MDAnalysisTests/lib/test_neighborsearch.py +++ b/testsuite/MDAnalysisTests/lib/test_neighborsearch.py @@ -42,7 +42,9 @@ def test_search(universe): """simply check that for a centered protein in a large box periodic and non-periodic return the same result""" ns = NeighborSearch.AtomNeighborSearch(universe.atoms) - pns = NeighborSearch.AtomNeighborSearch(universe.atoms, universe.atoms.dimensions) + pns = NeighborSearch.AtomNeighborSearch( + universe.atoms, universe.atoms.dimensions + ) ns_res = ns.search(universe.atoms[20], 20) pns_res = pns.search(universe.atoms[20], 20) diff --git a/testsuite/MDAnalysisTests/lib/test_nsgrid.py b/testsuite/MDAnalysisTests/lib/test_nsgrid.py index bde9b1079f..582e780172 100644 --- a/testsuite/MDAnalysisTests/lib/test_nsgrid.py +++ b/testsuite/MDAnalysisTests/lib/test_nsgrid.py @@ -134,7 +134,9 @@ def test_nsgrid_PBC_rect(): cutoff = 7 # FastNS is called differently to max coverage - searcher = nsgrid.FastNS(cutoff, universe.atoms.positions, box=universe.dimensions) + searcher = nsgrid.FastNS( + cutoff, universe.atoms.positions, box=universe.dimensions + ) results_grid = searcher.search( universe.atoms.positions[ref_id][None, :] @@ -206,7 +208,9 @@ def test_nsgrid_pairs(universe): results_grid = run_grid_search(universe, ref_id).get_pairs() - assert_equal(np.sort(neighbors, axis=0), np.sort(results_grid[:, 1], axis=0)) + assert_equal( + np.sort(neighbors, axis=0), np.sort(results_grid[:, 1], axis=0) + ) def test_nsgrid_pair_distances(universe): @@ -280,9 +284,9 @@ def test_nsgrid_distances(universe): ) def test_nsgrid_search(box, results): np.random.seed(90003) - points = (np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0)).astype( - np.float32 - ) + points = ( + np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0) + ).astype(np.float32) cutoff = 2.0 query = np.array([1.0, 1.0, 1.0], dtype=np.float32).reshape((1, 3)) @@ -316,9 +320,9 @@ def test_nsgrid_search(box, results): ) def test_nsgrid_selfsearch(box, result): np.random.seed(90003) - points = (np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0)).astype( - np.float32 - ) + points = ( + np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0) + ).astype(np.float32) cutoff = 1.0 if box is None or np.allclose(box[:3], 0): # create a pseudobox @@ -346,7 +350,9 @@ def test_nsgrid_probe_close_to_box_boundary(): # coordinate prior to PR #2136, so we ensure that this remains fixed. # See Issue #2132 for further information. ref = np.array([[55.783722, 44.190044, -54.16671]], dtype=np.float32) - box = np.array([53.785854, 43.951054, 57.17597, 90.0, 90.0, 90.0], dtype=np.float32) + box = np.array( + [53.785854, 43.951054, 57.17597, 90.0, 90.0, 90.0], dtype=np.float32 + ) cutoff = 3.0 # search within a configuration where we know the expected outcome: conf = np.ones((1, 3), dtype=np.float32) @@ -426,7 +432,9 @@ def test_issue_2229_part2(): u.atoms[0].position = [0, 0, 29.29] u.atoms[1].position = [0, 0, 28.23] - g = mda.lib.nsgrid.FastNS(3.0, u.atoms[[0]].positions, box=u.dimensions, pbc=False) + g = mda.lib.nsgrid.FastNS( + 3.0, u.atoms[[0]].positions, box=u.dimensions, pbc=False + ) assert len(g.search(u.atoms[[1]].positions).get_pairs()) == 1 g = mda.lib.nsgrid.FastNS(3.0, u.atoms[[1]].positions, box=u.dimensions) @@ -518,9 +526,9 @@ def high_mem_tests_enabled(): @pytest.mark.skipif(not high_mem_tests_enabled(), reason=reason) def test_issue_3183(): np.random.seed(90003) - points = (np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0)).astype( - np.float32 - ) + points = ( + np.random.uniform(low=0, high=1.0, size=(100, 3)) * (10.0) + ).astype(np.float32) cutoff = 2.0 query = np.array([1.0, 1.0, 1.0], dtype=np.float32).reshape((1, 3)) box = np.array([10000.0, 10000.0, 10000.0, 90.0, 90.0, 90.0]) diff --git a/testsuite/MDAnalysisTests/lib/test_util.py b/testsuite/MDAnalysisTests/lib/test_util.py index 0f9e357e4a..5db9b9afd4 100644 --- a/testsuite/MDAnalysisTests/lib/test_util.py +++ b/testsuite/MDAnalysisTests/lib/test_util.py @@ -282,14 +282,18 @@ def test_norm_range(self, x): v = r * np.array([np.cos(x), np.sin(x), 0]) assert_almost_equal(mdamath.norm(v), r, 6) - @pytest.mark.parametrize("vec1, vec2, value", [(e1, e2, e3), (e1, null, 0.0)]) + @pytest.mark.parametrize( + "vec1, vec2, value", [(e1, e2, e3), (e1, null, 0.0)] + ) def test_normal(self, vec1, vec2, value): assert_allclose(mdamath.normal(vec1, vec2), value) # add more non-trivial tests def test_angle_lower_clip(self): a = np.array([0.1, 0, 0.2]) - x = np.dot(a**0.5, -(a**0.5)) / (mdamath.norm(a**0.5) * mdamath.norm(-(a**0.5))) + x = np.dot(a**0.5, -(a**0.5)) / ( + mdamath.norm(a**0.5) * mdamath.norm(-(a**0.5)) + ) assert x < -1.0 assert mdamath.angle(a, -(a)) == np.pi assert mdamath.angle(a**0.5, -(a**0.5)) == np.pi @@ -379,7 +383,9 @@ def ref_tribox(self, tri_vecs): return box @pytest.mark.parametrize("lengths", comb_wr([-1, 0, 1, 2], 3)) - @pytest.mark.parametrize("angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3)) + @pytest.mark.parametrize( + "angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3) + ) def test_triclinic_vectors(self, lengths, angles): box = lengths + angles ref = self.ref_trivecs(box) @@ -455,7 +461,9 @@ def test_triclinic_vectors_box_cycle(self): for b in range(10, 91, 10): for g in range(10, 91, 10): ref = np.array([1, 1, 1, a, b, g], dtype=np.float32) - res = mdamath.triclinic_box(*mdamath.triclinic_vectors(ref)) + res = mdamath.triclinic_box( + *mdamath.triclinic_vectors(ref) + ) if not np.all(res == 0.0): assert_almost_equal(res, ref, 5) @@ -478,7 +486,9 @@ def test_triclinic_vectors_box_cycle_exact(self, angles): assert_allclose(res, ref) @pytest.mark.parametrize("lengths", comb_wr([-1, 0, 1, 2], 3)) - @pytest.mark.parametrize("angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3)) + @pytest.mark.parametrize( + "angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3) + ) def test_triclinic_box(self, lengths, angles): tri_vecs = self.ref_trivecs_unsafe(lengths + angles) ref = self.ref_tribox(tri_vecs) @@ -487,7 +497,9 @@ def test_triclinic_box(self, lengths, angles): assert res.dtype == ref.dtype @pytest.mark.parametrize("lengths", comb_wr([-1, 0, 1, 2], 3)) - @pytest.mark.parametrize("angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3)) + @pytest.mark.parametrize( + "angles", comb_wr([-10, 0, 20, 70, 90, 120, 180], 3) + ) def test_box_volume(self, lengths, angles): box = np.array(lengths + angles, dtype=np.float32) assert_almost_equal( @@ -765,11 +777,15 @@ def test_make_whole_fullerene(self): blengths = u.atoms.bonds.values() # kaboom u.atoms[::2].translate([u.dimensions[0], -2 * u.dimensions[1], 0.0]) - u.atoms[1::2].translate([0.0, 7 * u.dimensions[1], -5 * u.dimensions[2]]) + u.atoms[1::2].translate( + [0.0, 7 * u.dimensions[1], -5 * u.dimensions[2]] + ) mdamath.make_whole(u.atoms) - assert_array_almost_equal(u.atoms.bonds.values(), blengths, decimal=self.prec) + assert_array_almost_equal( + u.atoms.bonds.values(), blengths, decimal=self.prec + ) def test_make_whole_multiple_molecules(self): u = mda.Universe(two_water_gro, guess_bonds=True) @@ -1291,7 +1307,9 @@ def test_get_parser(self, extention, parser): ], ) @pytest.mark.parametrize("compression_extention", compressed_extensions) - def test_get_parser_compressed(self, extention, parser, compression_extention): + def test_get_parser_compressed( + self, extention, parser, compression_extention + ): file_name = "file.{0}{1}".format(extention, compression_extention) a = mda.topology.core.get_parser_for(file_name) @@ -1333,7 +1351,9 @@ def test_get_reader(self, extention, reader): ], ) @pytest.mark.parametrize("compression_extention", compressed_extensions) - def test_get_reader_compressed(self, extention, reader, compression_extention): + def test_get_reader_compressed( + self, extention, reader, compression_extention + ): file_name = "file.{0}{1}".format(extention, compression_extention) a = mda.coordinates.core.get_reader_for(file_name) @@ -1376,12 +1396,16 @@ class TestUniqueRows(object): def test_unique_rows_2(self): a = np.array([[0, 1], [1, 2], [2, 1], [0, 1], [0, 1], [2, 1]]) - assert_array_equal(util.unique_rows(a), np.array([[0, 1], [1, 2], [2, 1]])) + assert_array_equal( + util.unique_rows(a), np.array([[0, 1], [1, 2], [2, 1]]) + ) def test_unique_rows_3(self): a = np.array([[0, 1, 2], [0, 1, 2], [2, 3, 4], [0, 1, 2]]) - assert_array_equal(util.unique_rows(a), np.array([[0, 1, 2], [2, 3, 4]])) + assert_array_equal( + util.unique_rows(a), np.array([[0, 1, 2], [2, 3, 4]]) + ) def test_unique_rows_with_view(self): # unique_rows doesn't work when flags['OWNDATA'] is False, @@ -1427,7 +1451,9 @@ def test_file_no_extension(self): def test_wrong_format(self): # Make sure ``get_writer_for`` fails if the format is unknown with pytest.raises(TypeError): - mda.coordinates.core.get_writer_for(filename="fail_me", format="UNK") + mda.coordinates.core.get_writer_for( + filename="fail_me", format="UNK" + ) def test_compressed_extension(self): for ext in (".gz", ".bz2"): @@ -1446,7 +1472,9 @@ def test_compressed_extension_fail(self): def test_non_string_filename(self): # Does ``get_writer_for`` fails with non string filename, no format with pytest.raises(ValueError): - mda.coordinates.core.get_writer_for(filename=StringIO(), format=None) + mda.coordinates.core.get_writer_for( + filename=StringIO(), format=None + ) def test_multiframe_failure(self): # does ``get_writer_for`` fail with invalid format and multiframe not None @@ -1494,7 +1522,9 @@ def test_multiframe_nonsense(self): ) def test_singleframe(self, format, writer): assert ( - mda.coordinates.core.get_writer_for("this", format=format, multiframe=False) + mda.coordinates.core.get_writer_for( + "this", format=format, multiframe=False + ) == writer ) @@ -1508,7 +1538,9 @@ def test_singleframe(self, format, writer): ) def test_singleframe_fails(self, format): with pytest.raises(TypeError): - mda.coordinates.core.get_writer_for("this", format=format, multiframe=False) + mda.coordinates.core.get_writer_for( + "this", format=format, multiframe=False + ) @pytest.mark.parametrize( "format, writer", @@ -1520,33 +1552,49 @@ def test_singleframe_fails(self, format): ) def test_multiframe(self, format, writer): assert ( - mda.coordinates.core.get_writer_for("this", format=format, multiframe=True) + mda.coordinates.core.get_writer_for( + "this", format=format, multiframe=True + ) == writer ) @pytest.mark.parametrize( "format", - [format_tuple[0] for format_tuple in formats if format_tuple[3] is False], + [ + format_tuple[0] + for format_tuple in formats + if format_tuple[3] is False + ], ) def test_multiframe_fails(self, format): with pytest.raises(TypeError): - mda.coordinates.core.get_writer_for("this", format=format, multiframe=True) + mda.coordinates.core.get_writer_for( + "this", format=format, multiframe=True + ) def test_get_writer_for_pdb(self): assert ( - mda.coordinates.core.get_writer_for("this", format="PDB", multiframe=False) + mda.coordinates.core.get_writer_for( + "this", format="PDB", multiframe=False + ) == mda.coordinates.PDB.PDBWriter ) assert ( - mda.coordinates.core.get_writer_for("this", format="PDB", multiframe=True) + mda.coordinates.core.get_writer_for( + "this", format="PDB", multiframe=True + ) == mda.coordinates.PDB.MultiPDBWriter ) assert ( - mda.coordinates.core.get_writer_for("this", format="ENT", multiframe=False) + mda.coordinates.core.get_writer_for( + "this", format="ENT", multiframe=False + ) == mda.coordinates.PDB.PDBWriter ) assert ( - mda.coordinates.core.get_writer_for("this", format="ENT", multiframe=True) + mda.coordinates.core.get_writer_for( + "this", format="ENT", multiframe=True + ) == mda.coordinates.PDB.MultiPDBWriter ) @@ -1558,7 +1606,9 @@ def test_blocks_of_1(self): view = util.blocks_of(arr, 1, 1) assert view.shape == (4, 1, 1) - assert_array_almost_equal(view, np.array([[[0]], [[5]], [[10]], [[15]]])) + assert_array_almost_equal( + view, np.array([[[0]], [[5]], [[10]], [[15]]]) + ) # Change my view, check changes are reflected in arr view[:] = 1001 @@ -1781,11 +1831,14 @@ class TestWarnIfNotUnique(object): """Tests concerning the decorator @warn_if_not_unique""" def warn_msg(self, func, group, group_name): - msg = "{}.{}(): {} {} contains duplicates. Results might be " "biased!".format( - group.__class__.__name__, - func.__name__, - group_name, - group.__repr__(), + msg = ( + "{}.{}(): {} {} contains duplicates. Results might be " + "biased!".format( + group.__class__.__name__, + func.__name__, + group_name, + group.__repr__(), + ) ) return msg @@ -2158,7 +2211,9 @@ def test_atomgroup_mismatched_lengths(self): ag1 = u.select_atoms("index 0 to 10") ag2 = u.atoms - @check_coords("ag1", "ag2", check_lengths_match=True, allow_atomgroup=True) + @check_coords( + "ag1", "ag2", check_lengths_match=True, allow_atomgroup=True + ) def func(ag1, ag2): return ag1, ag2 @@ -2188,16 +2243,21 @@ def func(a): with pytest.raises(TypeError) as err: func(a_inv_type) assert err.msg == ( - "func(): Parameter 'a' must be a numpy.ndarray, " "got ." + "func(): Parameter 'a' must be a numpy.ndarray, " + "got ." ) with pytest.raises(ValueError) as err: func(a_inv_shape_1d) - assert err.msg == ("func(): a.shape must be (3,) or (n, 3), got " "(6,).") + assert err.msg == ( + "func(): a.shape must be (3,) or (n, 3), got " "(6,)." + ) with pytest.raises(ValueError) as err: func(a_inv_shape_2d) - assert err.msg == ("func(): a.shape must be (3,) or (n, 3), got " "(3, 2).") + assert err.msg == ( + "func(): a.shape must be (3,) or (n, 3), got " "(3, 2)." + ) def test_usage_with_kwargs(self): @@ -2359,7 +2419,9 @@ def AlternateUniverse(anything): assert re.search(deprecation_line_2, doc) if remove: - deprecation_line_3 = "`{0}` will be removed in release {1}".format(name, remove) + deprecation_line_3 = "`{0}` will be removed in release {1}".format( + name, remove + ) assert re.search(deprecation_line_3, doc) # check that the old docs are still present @@ -2413,7 +2475,9 @@ class TestCheckBox(object): np.array(["1", "1", 1, 90, "90", "90"]), np.array([1, 1, 1, 90, 90, 90], dtype=np.float32), np.array([1, 1, 1, 90, 90, 90], dtype=np.float64), - np.array([1, 1, 1, 1, 1, 1, 90, 90, 90, 90, 90, 90], dtype=np.float32)[::2], + np.array( + [1, 1, 1, 1, 1, 1, 90, 90, 90, 90, 90, 90], dtype=np.float32 + )[::2], ), ) def test_check_box_ortho(self, box): @@ -2437,7 +2501,9 @@ def test_check_box_None(self): np.array(["1", "1", 2, 45, "90", "90"]), np.array([1, 1, 2, 45, 90, 90], dtype=np.float32), np.array([1, 1, 2, 45, 90, 90], dtype=np.float64), - np.array([1, 1, 1, 1, 2, 2, 45, 45, 90, 90, 90, 90], dtype=np.float32)[::2], + np.array( + [1, 1, 1, 1, 2, 2, 45, 45, 90, 90, 90, 90], dtype=np.float32 + )[::2], ), ) def test_check_box_tri_vecs(self, box): diff --git a/testsuite/MDAnalysisTests/test_api.py b/testsuite/MDAnalysisTests/test_api.py index be46d34b5d..2819cd549a 100644 --- a/testsuite/MDAnalysisTests/test_api.py +++ b/testsuite/MDAnalysisTests/test_api.py @@ -75,7 +75,8 @@ def test_all_import(submodule): name for name in module.__all__ if name not in module.__dict__.keys() - and name not in [os.path.splitext(f)[0] for f in os.listdir(module_path)] + and name + not in [os.path.splitext(f)[0] for f in os.listdir(module_path)] ] assert_equal( missing, diff --git a/testsuite/MDAnalysisTests/topology/base.py b/testsuite/MDAnalysisTests/topology/base.py index 7aa48d3d07..e7649d65f8 100644 --- a/testsuite/MDAnalysisTests/topology/base.py +++ b/testsuite/MDAnalysisTests/topology/base.py @@ -57,12 +57,16 @@ def test_mandatory_attributes(self, top): # attributes required as part of the API # ALL parsers must provide these for attr in mandatory_attrs: - assert hasattr(top, attr), "Missing required attribute: {}".format(attr) + assert hasattr(top, attr), "Missing required attribute: {}".format( + attr + ) def test_expected_attributes(self, top): # Extra attributes as declared in specific implementations for attr in self.expected_attrs: - assert hasattr(top, attr), "Missing expected attribute: {}".format(attr) + assert hasattr(top, attr), "Missing expected attribute: {}".format( + attr + ) def test_no_unexpected_attributes(self, top): attrs = set( @@ -113,7 +117,9 @@ def test_guessed_attributes(self, filename): """check that the universe created with certain parser have the same guessed attributes as when it was guessed inside the parser""" u = mda.Universe(filename) - u_guessed_attrs = [attr.attrname for attr in u._topology.guessed_attributes] + u_guessed_attrs = [ + attr.attrname for attr in u._topology.guessed_attributes + ] for attr in self.guessed_attrs: assert hasattr(u.atoms, attr) assert attr in u_guessed_attrs diff --git a/testsuite/MDAnalysisTests/topology/test_fhiaims.py b/testsuite/MDAnalysisTests/topology/test_fhiaims.py index c7c46486f2..4086c107df 100644 --- a/testsuite/MDAnalysisTests/topology/test_fhiaims.py +++ b/testsuite/MDAnalysisTests/topology/test_fhiaims.py @@ -46,7 +46,9 @@ def test_guessed_types(self, filename): def test_guessed_masses(self, filename): u = mda.Universe(filename) - assert_allclose(u.atoms.masses, [15.999, 1.008, 1.008, 15.999, 1.008, 1.008]) + assert_allclose( + u.atoms.masses, [15.999, 1.008, 1.008, 15.999, 1.008, 1.008] + ) def test_elements(self, top): assert_equal(top.elements.values, ["O", "H", "H", "O", "H", "H"]) diff --git a/testsuite/MDAnalysisTests/topology/test_gms.py b/testsuite/MDAnalysisTests/topology/test_gms.py index 1597ec2e95..8becdfda6f 100644 --- a/testsuite/MDAnalysisTests/topology/test_gms.py +++ b/testsuite/MDAnalysisTests/topology/test_gms.py @@ -66,7 +66,9 @@ class TestGMSSYMOPT(GMSBase): ref_filename = GMS_SYMOPT def test_names(self, top): - assert_equal(top.names.values, ["CARBON", "CARBON", "HYDROGEN", "HYDROGEN"]) + assert_equal( + top.names.values, ["CARBON", "CARBON", "HYDROGEN", "HYDROGEN"] + ) def test_types(self, top): assert_equal(top.atomiccharges.values, [6, 6, 1, 1]) diff --git a/testsuite/MDAnalysisTests/topology/test_guessers.py b/testsuite/MDAnalysisTests/topology/test_guessers.py index 2f6004e4b5..69b1046f82 100644 --- a/testsuite/MDAnalysisTests/topology/test_guessers.py +++ b/testsuite/MDAnalysisTests/topology/test_guessers.py @@ -160,7 +160,9 @@ def bond_sort(arr): def test_guess_bonds_water(): u = mda.Universe(datafiles.two_water_gro) - bonds = bond_sort(guessers.guess_bonds(u.atoms, u.atoms.positions, u.dimensions)) + bonds = bond_sort( + guessers.guess_bonds(u.atoms, u.atoms.positions, u.dimensions) + ) assert_equal(bonds, ((0, 1), (0, 2), (3, 4), (3, 5))) diff --git a/testsuite/MDAnalysisTests/topology/test_itp.py b/testsuite/MDAnalysisTests/topology/test_itp.py index 6d305b549d..5b3cf93411 100644 --- a/testsuite/MDAnalysisTests/topology/test_itp.py +++ b/testsuite/MDAnalysisTests/topology/test_itp.py @@ -367,7 +367,9 @@ def test_defines(self, top): def test_guessed_masses(self, filename): u = mda.Universe(filename) - assert_allclose(u.atoms.masses, [15.999, 15.999, 15.999, 15.999, 15.999]) + assert_allclose( + u.atoms.masses, [15.999, 15.999, 15.999, 15.999, 15.999] + ) class TestITPKeywords(TestITPNoKeywords): @@ -392,7 +394,9 @@ def universe(self, filename): @pytest.fixture() def top(self, filename): with self.parser(filename) as p: - yield p.parse(FLEXIBLE=True, EXTRA_ATOMS=True, HW1_CHARGE=1, HW2_CHARGE=3) + yield p.parse( + FLEXIBLE=True, EXTRA_ATOMS=True, HW1_CHARGE=1, HW2_CHARGE=3 + ) def test_whether_settles_types(self, universe): for param in list(universe.bonds) + list(universe.angles): @@ -425,7 +429,9 @@ class TestNestedIfs(BaseITP): @pytest.fixture def universe(self, filename): - return mda.Universe(filename, HEAVY_H=True, EXTRA_ATOMS=True, HEAVY_SIX=True) + return mda.Universe( + filename, HEAVY_H=True, EXTRA_ATOMS=True, HEAVY_SIX=True + ) @pytest.fixture() def top(self, filename): @@ -459,7 +465,9 @@ def top(self, filename): @pytest.fixture() def universe(self, filename): - return mda.Universe(filename, topology_format="ITP", include_dir=GMX_DIR) + return mda.Universe( + filename, topology_format="ITP", include_dir=GMX_DIR + ) def test_output(self, filename): """Testing the call signature""" @@ -480,7 +488,9 @@ def test_guessed_attributes(self, filename): def test_sequential(self, universe): resids = np.array(list(range(2, 12)) + list(range(13, 23))) assert_equal(universe.residues.resids[:20], resids) - assert_equal(universe.residues.resindices, np.arange(self.expected_n_residues)) + assert_equal( + universe.residues.resindices, np.arange(self.expected_n_residues) + ) assert_equal(universe.atoms.chargegroups[-1], 63) diff --git a/testsuite/MDAnalysisTests/topology/test_lammpsdata.py b/testsuite/MDAnalysisTests/topology/test_lammpsdata.py index 96c40eefab..d384941237 100644 --- a/testsuite/MDAnalysisTests/topology/test_lammpsdata.py +++ b/testsuite/MDAnalysisTests/topology/test_lammpsdata.py @@ -300,7 +300,9 @@ def test_interpret_atom_style(): def test_interpret_atom_style_missing(): - with pytest.raises(ValueError, match="atom_style string missing required.+?"): + with pytest.raises( + ValueError, match="atom_style string missing required.+?" + ): style = mda.topology.LAMMPSParser.DATAParser._interpret_atom_style( "id charge z y x" ) diff --git a/testsuite/MDAnalysisTests/topology/test_minimal.py b/testsuite/MDAnalysisTests/topology/test_minimal.py index 761d1c91bc..2d0e1ffd87 100644 --- a/testsuite/MDAnalysisTests/topology/test_minimal.py +++ b/testsuite/MDAnalysisTests/topology/test_minimal.py @@ -104,7 +104,9 @@ def memory_possibilities(): yield array, order -memory_reader = pytest.mark.parametrize("array,order", list(memory_possibilities())) +memory_reader = pytest.mark.parametrize( + "array,order", list(memory_possibilities()) +) @memory_reader diff --git a/testsuite/MDAnalysisTests/topology/test_mol2.py b/testsuite/MDAnalysisTests/topology/test_mol2.py index ad588302ff..4157e8273a 100644 --- a/testsuite/MDAnalysisTests/topology/test_mol2.py +++ b/testsuite/MDAnalysisTests/topology/test_mol2.py @@ -224,7 +224,9 @@ def test_bond_orders(): def test_elements(): u = mda.Universe(mol2_molecule) - assert_equal(u.atoms.elements[:5], np.array(["N", "S", "N", "N", "O"], dtype="U3")) + assert_equal( + u.atoms.elements[:5], np.array(["N", "S", "N", "N", "O"], dtype="U3") + ) # Test for #2927 @@ -303,7 +305,9 @@ def test_partial_optional_columns(): def test_mol2_wo_required_columns(): - with pytest.raises(ValueError, match="The @ATOM block in mol2 file"): + with pytest.raises( + ValueError, match="The @ATOM block in mol2 file" + ): u = mda.Universe(StringIO(mol2_wo_required_col), format="MOL2") diff --git a/testsuite/MDAnalysisTests/topology/test_pdb.py b/testsuite/MDAnalysisTests/topology/test_pdb.py index ab740939bb..736e0f25f3 100644 --- a/testsuite/MDAnalysisTests/topology/test_pdb.py +++ b/testsuite/MDAnalysisTests/topology/test_pdb.py @@ -302,7 +302,10 @@ def test_missing_elements_noattribute(): 1) a warning is raised if elements are missing 2) the elements attribute is not set """ - wmsg = "Element information is missing, elements attribute will not be " "populated" + wmsg = ( + "Element information is missing, elements attribute will not be " + "populated" + ) with pytest.warns(UserWarning, match=wmsg): u = mda.Universe(PDB_small) with pytest.raises(AttributeError): diff --git a/testsuite/MDAnalysisTests/topology/test_pqr.py b/testsuite/MDAnalysisTests/topology/test_pqr.py index 5efffff96c..df3790b7a7 100644 --- a/testsuite/MDAnalysisTests/topology/test_pqr.py +++ b/testsuite/MDAnalysisTests/topology/test_pqr.py @@ -113,4 +113,6 @@ def test_gromacs_flavour(): assert_almost_equal(u.atoms[0].radius, 1.48, decimal=5) assert_almost_equal(u.atoms[0].charge, -0.67, decimal=5) # coordinatey things - assert_almost_equal(u.atoms[0].position, [15.710, 17.670, 23.340], decimal=4) + assert_almost_equal( + u.atoms[0].position, [15.710, 17.670, 23.340], decimal=4 + ) diff --git a/testsuite/MDAnalysisTests/topology/test_top.py b/testsuite/MDAnalysisTests/topology/test_top.py index 653ace458b..a67c9283b7 100644 --- a/testsuite/MDAnalysisTests/topology/test_top.py +++ b/testsuite/MDAnalysisTests/topology/test_top.py @@ -90,12 +90,18 @@ def test_angles_atom_counts(self, filename): def test_dihedrals_atom_counts(self, filename): u = mda.Universe(filename) assert len(u.atoms[[0]].dihedrals) == self.expected_n_zero_dihedrals - assert len(u.atoms[[self.atom_i]].dihedrals) == self.expected_n_i_dihedrals + assert ( + len(u.atoms[[self.atom_i]].dihedrals) + == self.expected_n_i_dihedrals + ) def test_impropers_atom_counts(self, filename): u = mda.Universe(filename) assert len(u.atoms[[0]].impropers) == self.expected_n_zero_impropers - assert len(u.atoms[[self.atom_i]].impropers) == self.expected_n_i_impropers + assert ( + len(u.atoms[[self.atom_i]].impropers) + == self.expected_n_i_impropers + ) def test_bonds_identity(self, top): vals = top.bonds.values @@ -144,7 +150,10 @@ def test_improper_atoms_bonded(self, top): backward = ((imp[0], imp[1]), (imp[1], imp[2]), (imp[1], imp[3])) for a, b in zip(forward, backward): assert ( - (b in vals) or (b[::-1] in vals) or (a in vals) or (a[::-1] in vals) + (b in vals) + or (b[::-1] in vals) + or (a in vals) + or (a[::-1] in vals) ) def test_elements(self, top): @@ -394,7 +403,9 @@ def test_chainIDs(self, filename): u = mda.Universe(filename) if hasattr(self, "expected_chainIDs"): - reschainIDs = [atomchainIDs[0] for atomchainIDs in u.residues.chainIDs] + reschainIDs = [ + atomchainIDs[0] for atomchainIDs in u.residues.chainIDs + ] assert_equal( reschainIDs, self.expected_chainIDs, "unexpected element match" ) @@ -779,9 +790,7 @@ class TestPRMEP(TOPBase): class TestErrorsAndWarnings(object): - ATOMIC_NUMBER_MSG = ( - "ATOMIC_NUMBER record not found, elements attribute will not be populated" - ) + ATOMIC_NUMBER_MSG = "ATOMIC_NUMBER record not found, elements attribute will not be populated" MISSING_ELEM_MSG = ( "Unknown ATOMIC_NUMBER value found for some atoms, " "these have been given an empty element record" diff --git a/testsuite/MDAnalysisTests/topology/test_topology_base.py b/testsuite/MDAnalysisTests/topology/test_topology_base.py index 16a7842e15..33d03258f9 100644 --- a/testsuite/MDAnalysisTests/topology/test_topology_base.py +++ b/testsuite/MDAnalysisTests/topology/test_topology_base.py @@ -6,7 +6,9 @@ class TestSquash(object): atom_resids = np.array([2, 2, 1, 1, 5, 5, 4, 4]) - atom_resnames = np.array(["A", "A", "B", "B", "C", "C", "D", "D"], dtype=object) + atom_resnames = np.array( + ["A", "A", "B", "B", "C", "C", "D", "D"], dtype=object + ) def test_squash(self): atom_residx, resids, (resnames,) = squash_by( diff --git a/testsuite/MDAnalysisTests/topology/test_tprparser.py b/testsuite/MDAnalysisTests/topology/test_tprparser.py index f8dc791144..b8ec5425d1 100644 --- a/testsuite/MDAnalysisTests/topology/test_tprparser.py +++ b/testsuite/MDAnalysisTests/topology/test_tprparser.py @@ -114,7 +114,9 @@ def test_molnums(self, top): def test_chainIDs(self, top): if hasattr(self, "ref_chainIDs"): - assert_equal(self.ref_chainIDs, getattr(top, "chainIDs").name_lookup) + assert_equal( + self.ref_chainIDs, getattr(top, "chainIDs").name_lookup + ) class TestTPR(TPRAttrs): @@ -341,7 +343,9 @@ def bonds_water(request): # The index of the first water atom is 1960 first = 1960 bonds = [ - bond for bond in parser.bonds.values if bond[0] >= first and bond[1] >= first + bond + for bond in parser.bonds.values + if bond[0] >= first and bond[1] >= first ] return bonds diff --git a/testsuite/MDAnalysisTests/topology/test_txyz.py b/testsuite/MDAnalysisTests/topology/test_txyz.py index 307beb7cb2..5615bdc985 100644 --- a/testsuite/MDAnalysisTests/topology/test_txyz.py +++ b/testsuite/MDAnalysisTests/topology/test_txyz.py @@ -61,7 +61,9 @@ def test_TXYZ_elements(): properly given a TXYZ file with valid elements record. """ u = mda.Universe(TXYZ, format="TXYZ") - element_list = np.array(["C", "H", "H", "O", "H", "C", "H", "H", "H"], dtype=object) + element_list = np.array( + ["C", "H", "H", "O", "H", "C", "H", "H", "H"], dtype=object + ) assert_equal(u.atoms.elements, element_list) diff --git a/testsuite/MDAnalysisTests/transformations/test_base.py b/testsuite/MDAnalysisTests/transformations/test_base.py index feb00838c5..492c2825b4 100644 --- a/testsuite/MDAnalysisTests/transformations/test_base.py +++ b/testsuite/MDAnalysisTests/transformations/test_base.py @@ -52,7 +52,9 @@ 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() diff --git a/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py b/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py index 06989267ed..a1d88b7840 100644 --- a/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py +++ b/testsuite/MDAnalysisTests/transformations/test_boxdimensions.py @@ -51,7 +51,9 @@ 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) + assert_array_almost_equal( + boxdimensions_universe.dimensions, new_dims, decimal=6 + ) @pytest.mark.parametrize( @@ -81,7 +83,9 @@ def test_dimensions_vector(boxdimensions_universe, dim_vector_shapes): "abcd", ), ) -def test_dimensions_vector_asarray(boxdimensions_universe, dim_vector_forms_dtypes): +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"): @@ -138,5 +142,9 @@ def test_varying_dimensions_no_data( ] ) 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 e74d9f6676..ecd4a87dd7 100644 --- a/testsuite/MDAnalysisTests/transformations/test_fit.py +++ b/testsuite/MDAnalysisTests/transformations/test_fit.py @@ -155,7 +155,9 @@ 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 diff --git a/testsuite/MDAnalysisTests/transformations/test_nojump.py b/testsuite/MDAnalysisTests/transformations/test_nojump.py index a6f9e56ac1..f295ec33a7 100644 --- a/testsuite/MDAnalysisTests/transformations/test_nojump.py +++ b/testsuite/MDAnalysisTests/transformations/test_nojump.py @@ -125,8 +125,12 @@ def nojump_universe_npt_2nd_frame_from_file(tmp_path_factory): 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: @@ -199,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 = [ @@ -297,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): diff --git a/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py b/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py index 0fbda82741..f3ae050f6b 100644 --- a/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py +++ b/testsuite/MDAnalysisTests/transformations/test_positionaveraging.py @@ -101,7 +101,9 @@ def test_posavging_specific(posaveraging_universes): for ts in posaveraging_universes.trajectory[fr_list]: np.copyto(specr_avgd[..., idx], ts.positions) 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): @@ -122,4 +124,6 @@ def test_posavging_specific_noreset(posaveraging_universes_noreset): for ts in posaveraging_universes_noreset.trajectory[fr_list]: np.copyto(specr_avgd[..., idx], ts.positions) 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 db2220fa4c..4f8fd9867b 100644 --- a/testsuite/MDAnalysisTests/transformations/test_rotate.py +++ b/testsuite/MDAnalysisTests/transformations/test_rotate.py @@ -36,7 +36,9 @@ 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.0, 373.0, 374.0, 90, 90, 90]) + transformed.trajectory.ts.dimensions = np.array( + [372.0, 373.0, 374.0, 90, 90, 90] + ) return reference, transformed @@ -72,7 +74,9 @@ def test_rotation_matrix(): 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? ref_u = rotate_universes[0] @@ -88,7 +92,9 @@ 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? ref_u = rotate_universes[0] @@ -151,7 +157,9 @@ def test_rotateby_atomgroup_cog_pbc(rotate_universes): 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) @@ -168,9 +176,9 @@ def test_rotateby_atomgroup_com_pbc(rotate_universes): 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) diff --git a/testsuite/MDAnalysisTests/transformations/test_translate.py b/testsuite/MDAnalysisTests/transformations/test_translate.py index 3961d88dff..ccb431f3c5 100644 --- a/testsuite/MDAnalysisTests/transformations/test_translate.py +++ b/testsuite/MDAnalysisTests/transformations/test_translate.py @@ -36,7 +36,9 @@ def translate_universes(): # 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.0, 373.0, 374.0, 90, 90, 90]) + transformed.trajectory.ts.dimensions = np.array( + [372.0, 373.0, 374.0, 90, 90, 90] + ) return reference, transformed @@ -76,7 +78,9 @@ def test_translate_transformations_api(translate_universes): 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): @@ -215,4 +219,6 @@ def test_center_transformations_api(translate_universes): 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 a35b03644c..a3439fb95c 100644 --- a/testsuite/MDAnalysisTests/transformations/test_wrap.py +++ b/testsuite/MDAnalysisTests/transformations/test_wrap.py @@ -93,11 +93,15 @@ def test_wrap_no_options(wrap_universes): ) -@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 ref.select_atoms("not resname SOL").wrap(compound=compound) - wrap(trans.select_atoms("not resname SOL"), compound=compound)(trans.trajectory.ts) + 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 ) diff --git a/testsuite/MDAnalysisTests/util.py b/testsuite/MDAnalysisTests/util.py index 27c4daef53..58cec2cbac 100644 --- a/testsuite/MDAnalysisTests/util.py +++ b/testsuite/MDAnalysisTests/util.py @@ -254,10 +254,13 @@ def __exit__(self, exc_type, exc_val, exc_tb): PendingDeprecationWarning, ) if any( - issubclass(c, deprecation_categories) for c in self._captured_categories + issubclass(c, deprecation_categories) + for c in self._captured_categories ): __tracebackhide__ = True - msg = "Produced DeprecationWarning or PendingDeprecationWarning" + msg = ( + "Produced DeprecationWarning or PendingDeprecationWarning" + ) raise AssertionError(msg) diff --git a/testsuite/MDAnalysisTests/utils/test_authors.py b/testsuite/MDAnalysisTests/utils/test_authors.py index eff77586d5..13563dadfd 100644 --- a/testsuite/MDAnalysisTests/utils/test_authors.py +++ b/testsuite/MDAnalysisTests/utils/test_authors.py @@ -26,4 +26,6 @@ def test_package_authors(): - assert len(MDAnalysis.__authors__) > 0, "Could not find the list of authors" + assert ( + len(MDAnalysis.__authors__) > 0 + ), "Could not find the list of authors" diff --git a/testsuite/MDAnalysisTests/utils/test_duecredit.py b/testsuite/MDAnalysisTests/utils/test_duecredit.py index fe07d6d1b0..c99f14dbf9 100644 --- a/testsuite/MDAnalysisTests/utils/test_duecredit.py +++ b/testsuite/MDAnalysisTests/utils/test_duecredit.py @@ -40,7 +40,10 @@ @pytest.mark.skipif( - (os.environ.get("DUECREDIT_ENABLE", "yes").lower() in ("no", "0", "false")), + ( + os.environ.get("DUECREDIT_ENABLE", "yes").lower() + in ("no", "0", "false") + ), reason="duecredit is explicitly disabled with DUECREDIT_ENABLE=no", ) class TestDuecredit(object): diff --git a/testsuite/MDAnalysisTests/utils/test_failure.py b/testsuite/MDAnalysisTests/utils/test_failure.py index 29ff10b846..494e84cdb9 100644 --- a/testsuite/MDAnalysisTests/utils/test_failure.py +++ b/testsuite/MDAnalysisTests/utils/test_failure.py @@ -28,4 +28,6 @@ def test_failure(): if "MDA_FAILURE_TEST" in os.environ: # Have a file open to trigger an output from the open_files plugin. f = open("./failure.txt", "w") - raise AssertionError("the MDA_FAILURE_TEST environment variable is set") + raise AssertionError( + "the MDA_FAILURE_TEST environment variable is set" + ) diff --git a/testsuite/MDAnalysisTests/utils/test_imports.py b/testsuite/MDAnalysisTests/utils/test_imports.py index aefbf59fa0..016388e324 100644 --- a/testsuite/MDAnalysisTests/utils/test_imports.py +++ b/testsuite/MDAnalysisTests/utils/test_imports.py @@ -61,5 +61,7 @@ def test_relative_import(testing_module): ): raise AssertionError( "A relative import statement was found in " - "module {testing_module} at linenumber {lineno}.".format(**vars()) + "module {testing_module} at linenumber {lineno}.".format( + **vars() + ) ) diff --git a/testsuite/MDAnalysisTests/utils/test_meta.py b/testsuite/MDAnalysisTests/utils/test_meta.py index a9790fe811..b6e536ef00 100644 --- a/testsuite/MDAnalysisTests/utils/test_meta.py +++ b/testsuite/MDAnalysisTests/utils/test_meta.py @@ -55,7 +55,9 @@ def test_version_format(version=None): r"(?P\d+)\.(?P\d+)\.(?P\d+)(-(?P\w+))?$", version, ) - assert m, "version {0} does not match the MAJOR.MINOR.PATCH(-suffix) format".format( + assert ( + m + ), "version {0} does not match the MAJOR.MINOR.PATCH(-suffix) format".format( version ) diff --git a/testsuite/MDAnalysisTests/utils/test_modelling.py b/testsuite/MDAnalysisTests/utils/test_modelling.py index a316fa2a64..c014c9f4d0 100644 --- a/testsuite/MDAnalysisTests/utils/test_modelling.py +++ b/testsuite/MDAnalysisTests/utils/test_modelling.py @@ -71,7 +71,9 @@ def capping(ref, ace, nma, output): "mobile": "resid {0} and backbone and not (resname NMA NME)".format( resid_max ), - "reference": "resid {0} and (backbone or name OT2)".format(resid_max), + "reference": "resid {0} and (backbone or name OT2)".format( + resid_max + ), }, strict=True, ) @@ -116,7 +118,9 @@ def test_capping_file(self, tmpdir): assert_equal(ace.resids[0], 1) assert_equal(nma.resids[0], 16) - assert_array_equal(peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions) + assert_array_equal( + peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions + ) def test_capping_inmemory(self, tmpdir): peptide = MDAnalysis.Universe(capping_input) @@ -138,7 +142,9 @@ def test_capping_inmemory(self, tmpdir): assert_equal(ace.resids[0], 1) assert_equal(nma.resids[0], 16) - assert_array_equal(peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions) + assert_array_equal( + peptide.trajectory.ts.dimensions, u.trajectory.ts.dimensions + ) @pytest.fixture() @@ -163,7 +169,9 @@ def u_without_coords(): class TestMerge(object): def test_merge(self, u_protein, u_ligand, u_water, tmpdir): - ids_before = [a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms] + ids_before = [ + a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms + ] # Do the merge u0 = MDAnalysis.Merge(u_protein.atoms, u_ligand.atoms, u_water.atoms) # Check that the output Universe has the same number of atoms as the @@ -176,11 +184,19 @@ def test_merge(self, u_protein, u_ligand, u_water, tmpdir): # segments as the starting AtomGroups assert_equal( len(u0.residues), - (len(u_protein.residues) + len(u_ligand.residues) + len(u_water.residues)), + ( + len(u_protein.residues) + + len(u_ligand.residues) + + len(u_water.residues) + ), ) assert_equal( len(u0.segments), - (len(u_protein.segments) + len(u_ligand.segments) + len(u_water.segments)), + ( + len(u_protein.segments) + + len(u_ligand.segments) + + len(u_water.segments) + ), ) # Make sure that all the atoms in the new universe are assigned to only @@ -192,7 +208,9 @@ def test_merge(self, u_protein, u_ligand, u_water, tmpdir): # Make sure that the atom ids of the original universes are unchanged, # ie we didn't make the original Universes 'dirty' - ids_after = [a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms] + ids_after = [ + a.index for u in [u_protein, u_ligand, u_water] for a in u.atoms + ] assert_equal( len(ids_after), (len(u_protein.atoms) + len(u_ligand.atoms) + len(u_water.atoms)), @@ -211,7 +229,9 @@ def test_merge(self, u_protein, u_ligand, u_water, tmpdir): assert_equal(ids_new, ids_new2) def test_merge_same_universe(self, u_protein): - u0 = MDAnalysis.Merge(u_protein.atoms, u_protein.atoms, u_protein.atoms) + u0 = MDAnalysis.Merge( + u_protein.atoms, u_protein.atoms, u_protein.atoms + ) assert_equal(len(u0.atoms), 3 * len(u_protein.atoms)) assert_equal(len(u0.residues), 3 * len(u_protein.residues)) assert_equal(len(u0.segments), 3 * len(u_protein.segments)) @@ -287,9 +307,18 @@ def test_merge_with_topology_from_different_universes(self, u, u_ligand): # PDB reader yields empty Bonds group, which means bonds from # PSF/DCD survive the merge # assert(not hasattr(u_merge.atoms, 'bonds') or len(u_merge.atoms.bonds) == 0) - assert not hasattr(u_merge.atoms, "angles") or len(u_merge.atoms.bonds) == 0 - assert not hasattr(u_merge.atoms, "dihedrals") or len(u_merge.atoms.bonds) == 0 - assert not hasattr(u_merge.atoms, "impropers") or len(u_merge.atoms.bonds) == 0 + assert ( + not hasattr(u_merge.atoms, "angles") + or len(u_merge.atoms.bonds) == 0 + ) + assert ( + not hasattr(u_merge.atoms, "dihedrals") + or len(u_merge.atoms.bonds) == 0 + ) + assert ( + not hasattr(u_merge.atoms, "impropers") + or len(u_merge.atoms.bonds) == 0 + ) def test_merge_without_topology(self, u): # This shouldn't have topology as we merged single atoms diff --git a/testsuite/MDAnalysisTests/utils/test_pickleio.py b/testsuite/MDAnalysisTests/utils/test_pickleio.py index 00c5b7307c..ae6c342cec 100644 --- a/testsuite/MDAnalysisTests/utils/test_pickleio.py +++ b/testsuite/MDAnalysisTests/utils/test_pickleio.py @@ -163,7 +163,9 @@ def test_pickle_with_write_mode(unpicklable_f, tmpdir): def test_GSD_pickle(): gsd_io = gsd_pickle_open(GSD, mode="r") gsd_io_pickled = pickle.loads(pickle.dumps(gsd_io)) - assert_equal(gsd_io[0].particles.position, gsd_io_pickled[0].particles.position) + assert_equal( + gsd_io[0].particles.position, gsd_io_pickled[0].particles.position + ) @pytest.mark.skipif(not HAS_GSD, reason="gsd not installed") @@ -187,7 +189,9 @@ def test_NCDF_mmap_pickle(): assert_equal(ncdf_io_pickled.use_mmap, False) -@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") +@pytest.mark.skipif( + not check_chemfiles_version(), reason="Wrong version of chemfiles" +) def test_Chemfiles_pickle(): chemfiles_io = ChemfilesPicklable(XYZ) chemfiles_io_pickled = pickle.loads(pickle.dumps(chemfiles_io)) @@ -198,10 +202,14 @@ def test_Chemfiles_pickle(): assert_equal(frame.positions[:], frame_pickled.positions[:]) -@pytest.mark.skipif(not check_chemfiles_version(), reason="Wrong version of chemfiles") +@pytest.mark.skipif( + not check_chemfiles_version(), reason="Wrong version of chemfiles" +) def test_Chemfiles_with_write_mode(tmpdir): with pytest.raises(ValueError, match=r"Only read mode"): - chemfiles_io = ChemfilesPicklable(tmpdir.mkdir("xyz").join("t.xyz"), mode="w") + chemfiles_io = ChemfilesPicklable( + tmpdir.mkdir("xyz").join("t.xyz"), mode="w" + ) @pytest.mark.skipif(not HAS_H5PY, reason="h5py not installed") diff --git a/testsuite/MDAnalysisTests/utils/test_qcprot.py b/testsuite/MDAnalysisTests/utils/test_qcprot.py index 206ad73b55..8ee971c227 100644 --- a/testsuite/MDAnalysisTests/utils/test_qcprot.py +++ b/testsuite/MDAnalysisTests/utils/test_qcprot.py @@ -47,7 +47,9 @@ @pytest.fixture() def atoms_a(): - return np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], dtype=np.float64) + return np.array( + [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], dtype=np.float64 + ) @pytest.fixture() diff --git a/testsuite/MDAnalysisTests/utils/test_selections.py b/testsuite/MDAnalysisTests/utils/test_selections.py index 4f31c50c12..212bce97da 100644 --- a/testsuite/MDAnalysisTests/utils/test_selections.py +++ b/testsuite/MDAnalysisTests/utils/test_selections.py @@ -42,7 +42,9 @@ class _SelectionWriter(object): filename = None - max_number = 357 # to keep fixtures smallish, only select CAs up to number 357 + max_number = ( + 357 # to keep fixtures smallish, only select CAs up to number 357 + ) @staticmethod @pytest.fixture() @@ -227,7 +229,9 @@ class TestSelectionWriter_Jmol(_SelectionWriter): def _assert_selectionstring(self, namedfile): header, indices = spt2array(namedfile.readline()) - assert_equal(header, self.ref_name, err_msg="SPT file has wrong selection name") + assert_equal( + header, self.ref_name, err_msg="SPT file has wrong selection name" + ) assert_array_equal( indices, self.ref_indices, diff --git a/testsuite/MDAnalysisTests/utils/test_streamio.py b/testsuite/MDAnalysisTests/utils/test_streamio.py index 417ec78509..56a421dda7 100644 --- a/testsuite/MDAnalysisTests/utils/test_streamio.py +++ b/testsuite/MDAnalysisTests/utils/test_streamio.py @@ -229,7 +229,9 @@ def test_join(self, tmpdir, funcname="join"): ) def test_expanduser_noexpansion_returns_NamedStream(self): - ns = self.create_NamedStream("de/zipferlack.txt") # no tilde ~ in name! + ns = self.create_NamedStream( + "de/zipferlack.txt" + ) # no tilde ~ in name! reference = ns.name value = os.path.expanduser(ns) assert_equal( @@ -446,7 +448,9 @@ def test_MOL2Reader(self, streamData): assert_equal(len(u.atoms), 49) assert_equal(u.trajectory.n_frames, 200) u.trajectory[199] - assert_array_almost_equal(u.atoms.positions[0], [1.7240, 11.2730, 14.1200]) + assert_array_almost_equal( + u.atoms.positions[0], [1.7240, 11.2730, 14.1200] + ) def test_XYZReader(self, streamData): u = MDAnalysis.Universe( @@ -455,7 +459,9 @@ def test_XYZReader(self, streamData): ) assert_equal(len(u.atoms), 8) assert_equal(u.trajectory.n_frames, 3) - assert_equal(u.trajectory.frame, 0) # weird, something odd with XYZ reader + assert_equal( + u.trajectory.frame, 0 + ) # weird, something odd with XYZ reader u.trajectory.next() # (should really only need one next()... ) assert_equal(u.trajectory.frame, 1) # !!!! ??? u.trajectory.next() # frame 2 diff --git a/testsuite/MDAnalysisTests/utils/test_transformations.py b/testsuite/MDAnalysisTests/utils/test_transformations.py index d6a0795b89..72d6831cd1 100644 --- a/testsuite/MDAnalysisTests/utils/test_transformations.py +++ b/testsuite/MDAnalysisTests/utils/test_transformations.py @@ -230,7 +230,9 @@ def test_projection_from_matrix_2(self, data): def test_projection_from_matrix_3(self, data): point, normal, direct, persp = data - P0 = t.projection_matrix(point, normal, perspective=persp, pseudo=False) + P0 = t.projection_matrix( + point, normal, perspective=persp, pseudo=False + ) result = t.projection_from_matrix(P0, pseudo=False) P1 = t.projection_matrix(*result) assert_equal(t.is_same_transform(P0, P1), True) @@ -535,7 +537,9 @@ def test_quaternion_from_matrix_2(self, f): def test_quaternion_from_matrix_3(self, f): R = t.rotation_matrix(0.123, (1, 2, 3)) q = f(R, True) - assert_allclose(q, [0.9981095, 0.0164262, 0.0328524, 0.0492786], atol=_ATOL) + assert_allclose( + q, [0.9981095, 0.0164262, 0.0328524, 0.0492786], atol=_ATOL + ) def test_quaternion_from_matrix_4(self, f): R = [ diff --git a/testsuite/MDAnalysisTests/utils/test_units.py b/testsuite/MDAnalysisTests/utils/test_units.py index 31f41b0352..8121188c1c 100644 --- a/testsuite/MDAnalysisTests/utils/test_units.py +++ b/testsuite/MDAnalysisTests/utils/test_units.py @@ -39,7 +39,9 @@ def test_unicode_encoding_with_symbol(self): try: assert_equal(units.lengthUnit_factor["Å"], 1.0) except KeyError: - raise AssertionError("UTF-8-encoded symbol for Angtrom not supported") + raise AssertionError( + "UTF-8-encoded symbol for Angtrom not supported" + ) class TestConstants(object): diff --git a/testsuite/MDAnalysisTests/visualization/test_streamlines.py b/testsuite/MDAnalysisTests/visualization/test_streamlines.py index 6902bed671..80bd4299cf 100644 --- a/testsuite/MDAnalysisTests/visualization/test_streamlines.py +++ b/testsuite/MDAnalysisTests/visualization/test_streamlines.py @@ -172,7 +172,9 @@ def test_per_core_work_2D(membrane_xtc, univ): ymin = univ.atoms.positions[..., 1].min() ymax = univ.atoms.positions[..., 1].max() tuple_of_limits = (xmin, xmax, ymin, ymax) - grid = streamlines.produce_grid(tuple_of_limits=tuple_of_limits, grid_spacing=20) + grid = streamlines.produce_grid( + tuple_of_limits=tuple_of_limits, grid_spacing=20 + ) ( list_square_vertex_arrays_per_core, list_parent_index_values, @@ -182,7 +184,9 @@ def test_per_core_work_2D(membrane_xtc, univ): values = streamlines.per_core_work( topology_file_path=Martini_membrane_gro, trajectory_file_path=membrane_xtc, - list_square_vertex_arrays_this_core=list_square_vertex_arrays_per_core[0], + list_square_vertex_arrays_this_core=list_square_vertex_arrays_per_core[ + 0 + ], MDA_selection="name PO4", start_frame=1, end_frame=2, From b1ee485a6db10db252b6ee89cac83fe527cf2cfb Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Mon, 28 Jul 2025 15:51:37 -0400 Subject: [PATCH 10/26] added test for all msd types - added test with start stop step --- package/CHANGELOG | 8 +- package/MDAnalysis/analysis/msd.py | 12 +- .../MDAnalysisTests/analysis/test_msd.py | 678 ++++++++++++++---- .../custom_non_linear/test_non_linear.dump | 264 ------- .../test_non_linear.dump.bz2 | Bin 0 -> 2210 bytes testsuite/MDAnalysisTests/datafiles.py | 4 +- 6 files changed, 552 insertions(+), 414 deletions(-) delete mode 100644 testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump create mode 100644 testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump.bz2 diff --git a/package/CHANGELOG b/package/CHANGELOG index e5dce0d11c..99094375c6 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -40,6 +40,9 @@ Fixes directly passing them. (Issue #3520, PR #5006) Enhancements + * Added capability to calculate MSD from frames with irregular (non-linear) + time spacing in analysis.msd.EinsteinMSD with keyword argument + `non_linear=True` (Issue #5028, PR #5066) * Added `TemplateInferrer` and `RDKitInferrer` dataclasses to the `RDKitInferring` module to be used by the RDKit converter. (PR #4305) * Improve speed of GROMOS11 (TRC) reader (Issue #5079, PR #5080) @@ -63,11 +66,6 @@ Enhancements (PR #5038) * Moved distopia checking function to common import location in MDAnalysisTest.util (PR #5038) - * Added new method '_conclude_non_linear` to calculate time-averaged - mean square displacement in `package/MDAnalysis/analysis/msd.py`, - new bool keyword argument `non_linear=True` under `EinsteinMSD` - enables execution of this method. - (Issue #5028, PR #5066) Changes * Refactored the RDKit converter code to move the inferring code in a separate diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index e354dc0ac4..cd1ed618aa 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -287,6 +287,9 @@ class EinsteinMSD(AnalysisBase): non-linearly dumped. To use this set `fft=False`. Defaults to ``False``. + .. versionadded:: 2.10.0 + + Attributes ---------- dim_fac : int @@ -296,7 +299,11 @@ class EinsteinMSD(AnalysisBase): results.msds_by_particle : :class:`numpy.ndarray` The MSD of each individual particle with respect to lag-time. results.delta_t_values : :class:`numpy.ndarray` - Array of unique Δt (time differences) at which time-averaged MSD values are computed. + Array of unique Δt (time differences) at which time-averaged MSD values are + computed. + + .. versionadded:: 2.10.0 + ag : :class:`AtomGroup` The :class:`AtomGroup` resulting from your selection n_frames : int @@ -305,7 +312,10 @@ class EinsteinMSD(AnalysisBase): Number of particles MSD was calculated over. + .. versionadded:: 2.0.0 .. versionadded:: 2.10.0 + Added ability to calculate MSD from samples that are not linearly spaced with the + new `non_linear` keyword argument. """ def __init__( diff --git a/testsuite/MDAnalysisTests/analysis/test_msd.py b/testsuite/MDAnalysisTests/analysis/test_msd.py index 29435ab470..35b9617fc7 100644 --- a/testsuite/MDAnalysisTests/analysis/test_msd.py +++ b/testsuite/MDAnalysisTests/analysis/test_msd.py @@ -25,7 +25,7 @@ from MDAnalysis.analysis.msd import EinsteinMSD as MSD import MDAnalysis as mda -from numpy.testing import assert_almost_equal, assert_equal +from numpy.testing import assert_almost_equal, assert_equal, assert_allclose import numpy as np from MDAnalysisTests.datafiles import ( @@ -51,6 +51,11 @@ def u(): return mda.Universe(PSF, DCD) +@pytest.fixture(scope="module") +def u_nonlinear(): + return mda.Universe(LAMMPSDUMP_non_linear, format="LAMMPSDUMP") + + @pytest.fixture(scope="module") def NSTEP(): nstep = 5000 @@ -130,7 +135,9 @@ def test_msdtype_error(self, u, SELECTION, msdtype): ("z", 1), ], ) - def test_simple_step_traj_all_dims(self, step_traj, NSTEP, dim, dim_factor): + def test_simple_step_traj_all_dims( + self, step_traj, NSTEP, dim, dim_factor + ): # testing the "simple" algorithm on constant velocity trajectory # should fit the polynomial y=dim_factor*x**2 m_simple = MSD(step_traj, "all", msd_type=dim, fft=False) @@ -150,14 +157,18 @@ def test_simple_step_traj_all_dims(self, step_traj, NSTEP, dim, dim_factor): ("z", 1), ], ) - def test_simple_start_stop_step_all_dims(self, step_traj, NSTEP, dim, dim_factor): + def test_simple_start_stop_step_all_dims( + self, step_traj, NSTEP, dim, dim_factor + ): # testing the "simple" algorithm on constant velocity trajectory # test start stop step is working correctly m_simple = MSD(step_traj, "all", msd_type=dim, fft=False) m_simple.run(start=10, stop=1000, step=10) poly = characteristic_poly(NSTEP, dim_factor) # polynomial must take offset start into account - assert_almost_equal(m_simple.results.timeseries, poly[0:990:10], decimal=4) + assert_almost_equal( + m_simple.results.timeseries, poly[0:990:10], decimal=4 + ) def test_random_walk_u_simple(self, random_walk_u): # regress against random_walk test data @@ -252,14 +263,18 @@ def test_fft_step_traj_all_dims(self, step_traj, NSTEP, dim, dim_factor): ("z", 1), ], ) - def test_fft_start_stop_step_all_dims(self, step_traj, NSTEP, dim, dim_factor): + def test_fft_start_stop_step_all_dims( + self, step_traj, NSTEP, dim, dim_factor + ): # testing the fft algorithm on constant velocity trajectory # test start stop step is working correctly m_simple = MSD(step_traj, "all", msd_type=dim, fft=True) m_simple.run(start=10, stop=1000, step=10) poly = characteristic_poly(NSTEP, dim_factor) # polynomial must take offset start into account - assert_almost_equal(m_simple.results.timeseries, poly[0:990:10], decimal=3) + assert_almost_equal( + m_simple.results.timeseries, poly[0:990:10], decimal=3 + ) def test_random_walk_u_fft(self, random_walk_u): # regress against random_walk test data @@ -270,142 +285,521 @@ def test_random_walk_u_fft(self, random_walk_u): assert_almost_equal(norm, val, decimal=5) -def test_msd_non_linear(): - u = mda.Universe(LAMMPSDUMP_non_linear, format="LAMMPSDUMP") - - msd = MSD(u, select="all", msd_type="xyz", non_linear=True) - msd.run() - - result_msd = msd.results.timeseries - result_delta_t = msd.results.delta_t_values - - assert result_msd.ndim == 1 - assert result_msd.shape[0] > 0 +class TestMSDNonLinear: - assert result_delta_t.ndim == 1 - assert result_delta_t.shape[0] > 0 - - expected_msd = np.array( - [ - 0.00000000e00, - 7.70976963e-05, - 2.90842662e-04, - 6.55040347e-04, - 1.20610926e-03, - 2.52547250e-03, - 3.31645965e-03, - 5.38852795e-03, - 1.01941562e-02, - 1.24745603e-02, - 1.35380300e-02, - 1.57475527e-02, - 2.85165801e-02, - 3.50591021e-02, - 3.81292797e-02, - 3.96176470e-02, - 3.83551274e-02, - 5.51041371e-02, - 5.95049433e-02, - 6.07026502e-02, - 6.14434181e-02, - 6.19512436e-02, - 6.61293773e-02, - 9.46607497e-02, - 1.01300585e-01, - 9.96583811e-02, - 9.81112279e-02, - 9.72780657e-02, - 9.69221886e-02, - 1.29442431e-01, - 1.80752226e-01, - 1.86358673e-01, - 1.98140564e-01, - 2.00603000e-01, - 1.99094789e-01, - 1.97272787e-01, - 1.96156023e-01, - 2.67664446e-01, - 4.50987076e-01, - 4.02344442e-01, - 3.91458056e-01, - 4.10370922e-01, - 4.22997445e-01, - 4.26217251e-01, - 4.26484034e-01, - 4.26360794e-01, - 6.91315347e-01, - 9.94317423e-01, - 1.19622365e00, - 1.04919180e00, - 1.06437594e00, - 1.09426432e00, - 1.10194082e00, - 1.10275424e00, - 1.10383947e00, - 1.10493159e00, - ] - ) - - expected_delta_t = np.array( + @pytest.mark.parametrize( + "dim, dim_factor", [ - 0.000e00, - 1.000e00, - 2.000e00, - 3.000e00, - 4.000e00, - 6.000e00, - 7.000e00, - 8.000e00, - 1.200e01, - 1.400e01, - 1.500e01, - 1.600e01, - 2.400e01, - 2.800e01, - 3.000e01, - 3.100e01, - 3.200e01, - 4.800e01, - 5.600e01, - 6.000e01, - 6.200e01, - 6.300e01, - 6.400e01, - 9.600e01, - 1.120e02, - 1.200e02, - 1.240e02, - 1.260e02, - 1.270e02, - 1.280e02, - 1.920e02, - 2.240e02, - 2.400e02, - 2.480e02, - 2.520e02, - 2.540e02, - 2.550e02, - 2.560e02, - 3.840e02, - 4.480e02, - 4.800e02, - 4.960e02, - 5.040e02, - 5.080e02, - 5.100e02, - 5.110e02, - 5.120e02, - 7.680e02, - 8.960e02, - 9.600e02, - 9.920e02, - 1.008e03, - 1.016e03, - 1.020e03, - 1.022e03, - 1.023e03, - ] + ("xyz", 3), + ("xy", 2), + ("xz", 2), + ("yz", 2), + ("x", 1), + ("y", 1), + ("z", 1), + ], ) - - np.testing.assert_allclose(result_msd, expected_msd, rtol=1e-5) - np.testing.assert_allclose(result_delta_t, expected_delta_t, rtol=1e-5) + def test_all_msd_types(self, u_nonlinear, dim, dim_factor): + msd = MSD(u_nonlinear, select="all", msd_type=dim, non_linear=True) + msd.run() + result_msd = msd.results.timeseries + result_delta_t = msd.results.delta_t_values + expected_results_msd = { + "xyz": np.array( + [ + 0.00000000e00, + 7.70976963e-05, + 2.90842662e-04, + 6.55040347e-04, + 1.20610926e-03, + 2.52547250e-03, + 3.31645965e-03, + 5.38852795e-03, + 1.01941562e-02, + 1.24745603e-02, + 1.35380300e-02, + 1.57475527e-02, + 2.85165801e-02, + 3.50591021e-02, + 3.81292797e-02, + 3.96176470e-02, + 3.83551274e-02, + 5.51041371e-02, + 5.95049433e-02, + 6.07026502e-02, + 6.14434181e-02, + 6.19512436e-02, + 6.61293773e-02, + 9.46607497e-02, + 1.01300585e-01, + 9.96583811e-02, + 9.81112279e-02, + 9.72780657e-02, + 9.69221886e-02, + 1.29442431e-01, + 1.80752226e-01, + 1.86358673e-01, + 1.98140564e-01, + 2.00603000e-01, + 1.99094789e-01, + 1.97272787e-01, + 1.96156023e-01, + 2.67664446e-01, + 4.50987076e-01, + 4.02344442e-01, + 3.91458056e-01, + 4.10370922e-01, + 4.22997445e-01, + 4.26217251e-01, + 4.26484034e-01, + 4.26360794e-01, + 6.91315347e-01, + 9.94317423e-01, + 1.19622365e00, + 1.04919180e00, + 1.06437594e00, + 1.09426432e00, + 1.10194082e00, + 1.10275424e00, + 1.10383947e00, + 1.10493159e00, + ] + ), + "xy": np.array( + [ + 0.00000000e00, + 4.71534353e-05, + 2.00284753e-04, + 4.34113725e-04, + 9.36004413e-04, + 1.92444776e-03, + 2.48128885e-03, + 3.74869519e-03, + 7.45690928e-03, + 9.32883150e-03, + 1.02001429e-02, + 1.18451152e-02, + 2.16722754e-02, + 2.69028318e-02, + 2.92942088e-02, + 3.04040224e-02, + 3.09111456e-02, + 4.32505110e-02, + 4.71624323e-02, + 4.84247750e-02, + 4.88898846e-02, + 4.91026665e-02, + 5.18382213e-02, + 7.64373669e-02, + 8.16001408e-02, + 7.79840283e-02, + 7.61576850e-02, + 7.51756311e-02, + 7.46696051e-02, + 6.91138291e-02, + 1.32156093e-01, + 1.32978164e-01, + 1.52259070e-01, + 1.47420312e-01, + 1.46571506e-01, + 1.46636604e-01, + 1.46716952e-01, + 1.49788156e-01, + 2.34954789e-01, + 2.15475722e-01, + 1.99697304e-01, + 2.35851828e-01, + 2.39591438e-01, + 2.41774318e-01, + 2.43132227e-01, + 2.43853085e-01, + 4.73633489e-01, + 8.32733529e-01, + 1.01977895e00, + 8.72773844e-01, + 8.63705171e-01, + 9.10979795e-01, + 9.22629515e-01, + 9.24681213e-01, + 9.26321374e-01, + 9.27520965e-01, + ] + ), + "xz": np.array( + [ + 0.00000000e00, + 4.16965032e-05, + 1.32580865e-04, + 3.15741675e-04, + 5.00108758e-04, + 1.02934249e-03, + 1.37025814e-03, + 3.14244287e-03, + 5.31340742e-03, + 6.09128877e-03, + 6.42306131e-03, + 1.20010188e-02, + 1.98178137e-02, + 2.30804487e-02, + 2.44381472e-02, + 2.50944884e-02, + 2.58745154e-02, + 3.91995598e-02, + 4.33821430e-02, + 4.39535754e-02, + 4.42724505e-02, + 4.45635874e-02, + 3.41294299e-02, + 4.98672274e-02, + 5.84413430e-02, + 6.25792031e-02, + 6.41470811e-02, + 6.45891296e-02, + 6.47562187e-02, + 1.09986645e-01, + 1.43454970e-01, + 1.33856061e-01, + 1.39832186e-01, + 1.43856499e-01, + 1.43524801e-01, + 1.42333307e-01, + 1.41539074e-01, + 1.92375956e-01, + 3.44024779e-01, + 3.28460560e-01, + 3.16161165e-01, + 3.18352125e-01, + 3.24388442e-01, + 3.26201142e-01, + 3.26221383e-01, + 3.26069834e-01, + 3.57054087e-01, + 4.65715415e-01, + 5.33167435e-01, + 5.24342584e-01, + 5.54527169e-01, + 5.31925547e-01, + 5.20297822e-01, + 5.15474719e-01, + 5.14206075e-01, + 5.14110889e-01, + ] + ), + "yz": np.array( + [ + 0.00000000e00, + 6.53454542e-05, + 2.48819706e-04, + 5.60225294e-04, + 9.76105353e-04, + 2.09715474e-03, + 2.78137231e-03, + 3.88591783e-03, + 7.61799579e-03, + 9.52900038e-03, + 1.04528558e-02, + 7.64897138e-03, + 1.55430710e-02, + 2.01349237e-02, + 2.25262033e-02, + 2.37367832e-02, + 1.99245940e-02, + 2.77582034e-02, + 2.84653112e-02, + 2.90269501e-02, + 2.97245011e-02, + 3.02362334e-02, + 4.62911034e-02, + 6.30169052e-02, + 6.25596862e-02, + 5.87535308e-02, + 5.59176898e-02, + 5.47913707e-02, + 5.44185534e-02, + 7.97843873e-02, + 8.58933884e-02, + 1.05883121e-01, + 1.04189871e-01, + 1.09929188e-01, + 1.08093271e-01, + 1.05575663e-01, + 1.04056021e-01, + 1.93164780e-01, + 3.22994584e-01, + 2.60752603e-01, + 2.67057643e-01, + 2.66537890e-01, + 2.82015010e-01, + 2.84459043e-01, + 2.83614457e-01, + 2.82798669e-01, + 5.51943117e-01, + 6.90185902e-01, + 8.39500901e-01, + 7.01267168e-01, + 7.10519535e-01, + 7.45623290e-01, + 7.60954298e-01, + 7.65352545e-01, + 7.67151495e-01, + 7.68231328e-01, + ] + ), + "x": np.array( + [ + 0.00000000e00, + 1.17522422e-05, + 4.20229558e-05, + 9.48150526e-05, + 2.30003909e-04, + 4.28317752e-04, + 5.35087342e-04, + 1.50261012e-03, + 2.57616045e-03, + 2.94555994e-03, + 3.08517422e-03, + 8.09858129e-03, + 1.29735090e-02, + 1.49241784e-02, + 1.56030763e-02, + 1.58808638e-02, + 1.84305335e-02, + 2.73459337e-02, + 3.10396321e-02, + 3.16757002e-02, + 3.17189170e-02, + 3.17150102e-02, + 1.98382739e-02, + 3.16438446e-02, + 3.87408988e-02, + 4.09048503e-02, + 4.21935381e-02, + 4.24866950e-02, + 4.25036352e-02, + 4.96580433e-02, + 9.48588375e-02, + 8.04755522e-02, + 9.39506926e-02, + 9.06738115e-02, + 9.10015182e-02, + 9.16971239e-02, + 9.21000022e-02, + 7.44996658e-02, + 1.27992492e-01, + 1.41591839e-01, + 1.24400413e-01, + 1.43833032e-01, + 1.40982435e-01, + 1.41758209e-01, + 1.42869576e-01, + 1.43562125e-01, + 1.39372230e-01, + 3.04131521e-01, + 3.56722744e-01, + 3.47924630e-01, + 3.53856403e-01, + 3.48641025e-01, + 3.40986519e-01, + 3.37401693e-01, + 3.36687977e-01, + 3.36700263e-01, + ] + ), + "y": np.array( + [ + 0.00000000e00, + 3.54011931e-05, + 1.58261797e-04, + 3.39298672e-04, + 7.06000504e-04, + 1.49613000e-03, + 1.94620151e-03, + 2.24608508e-03, + 4.88074882e-03, + 6.38327155e-03, + 7.11496870e-03, + 3.74653386e-03, + 8.69876636e-03, + 1.19786534e-02, + 1.36911325e-02, + 1.45231586e-02, + 1.24806121e-02, + 1.59045773e-02, + 1.61228002e-02, + 1.67490749e-02, + 1.71709676e-02, + 1.73876563e-02, + 3.19999474e-02, + 4.47935223e-02, + 4.28592420e-02, + 3.70791780e-02, + 3.39641469e-02, + 3.26889361e-02, + 3.21659699e-02, + 1.94557858e-02, + 3.72972556e-02, + 5.25026117e-02, + 5.83083776e-02, + 5.67465008e-02, + 5.55699879e-02, + 5.49394802e-02, + 5.46169493e-02, + 7.52884900e-02, + 1.06962297e-01, + 7.38838824e-02, + 7.52968914e-02, + 9.20187962e-02, + 9.86090028e-02, + 1.00016109e-01, + 1.00262650e-01, + 1.00290960e-01, + 3.34261260e-01, + 5.28602008e-01, + 6.63056210e-01, + 5.24849214e-01, + 5.09848769e-01, + 5.62338769e-01, + 5.81642995e-01, + 5.87279520e-01, + 5.89633397e-01, + 5.90820702e-01, + ] + ), + "z": np.array( + [ + 0.00000000e00, + 2.99442610e-05, + 9.05579089e-05, + 2.20926622e-04, + 2.70104849e-04, + 6.01024741e-04, + 8.35170802e-04, + 1.63983276e-03, + 2.73724696e-03, + 3.14572883e-03, + 3.33788709e-03, + 3.90243752e-03, + 6.84430468e-03, + 8.15627028e-03, + 8.83507087e-03, + 9.21362461e-03, + 7.44398187e-03, + 1.18536261e-02, + 1.23425110e-02, + 1.22778752e-02, + 1.25535335e-02, + 1.28485771e-02, + 1.42911560e-02, + 1.82233829e-02, + 1.97004442e-02, + 2.16743528e-02, + 2.19535430e-02, + 2.21024346e-02, + 2.22525835e-02, + 6.03286015e-02, + 4.85961328e-02, + 5.33805088e-02, + 4.58814937e-02, + 5.31826873e-02, + 5.25232828e-02, + 5.06361832e-02, + 4.94390715e-02, + 1.17876290e-01, + 2.16032287e-01, + 1.86868721e-01, + 1.91760752e-01, + 1.74519093e-01, + 1.83406007e-01, + 1.84442934e-01, + 1.83351807e-01, + 1.82507709e-01, + 2.17681858e-01, + 1.61583894e-01, + 1.76444690e-01, + 1.76417954e-01, + 2.00670767e-01, + 1.83284521e-01, + 1.79311302e-01, + 1.78073026e-01, + 1.77518098e-01, + 1.77410626e-01, + ] + ), + } + expected_delta_t = np.array( + [ + 0.000e00, + 1.000e00, + 2.000e00, + 3.000e00, + 4.000e00, + 6.000e00, + 7.000e00, + 8.000e00, + 1.200e01, + 1.400e01, + 1.500e01, + 1.600e01, + 2.400e01, + 2.800e01, + 3.000e01, + 3.100e01, + 3.200e01, + 4.800e01, + 5.600e01, + 6.000e01, + 6.200e01, + 6.300e01, + 6.400e01, + 9.600e01, + 1.120e02, + 1.200e02, + 1.240e02, + 1.260e02, + 1.270e02, + 1.280e02, + 1.920e02, + 2.240e02, + 2.400e02, + 2.480e02, + 2.520e02, + 2.540e02, + 2.550e02, + 2.560e02, + 3.840e02, + 4.480e02, + 4.800e02, + 4.960e02, + 5.040e02, + 5.080e02, + 5.100e02, + 5.110e02, + 5.120e02, + 7.680e02, + 8.960e02, + 9.600e02, + 9.920e02, + 1.008e03, + 1.016e03, + 1.020e03, + 1.022e03, + 1.023e03, + ] + ) + expected_msd = expected_results_msd[dim] + assert result_msd.shape == expected_msd.shape + assert result_delta_t.shape == expected_delta_t.shape + assert_allclose(result_msd, expected_msd, rtol=1e-5) + assert_allclose(result_delta_t, expected_delta_t, rtol=1e-5) + + def test_start_stop_step(self, u_nonlinear): + msd = MSD(u_nonlinear, select="all", msd_type="xyz", non_linear=True) + msd.run(start=3, stop=9, step=2) + result_msd = msd.results.timeseries + result_delta_t = msd.results.delta_t_values + expected_msd = np.array([0.0, 0.02851658, 0.09466075, 0.09965838]) + expected_delta_t = np.array([0.0, 24.0, 96.0, 120.0]) + assert result_msd.shape == expected_msd.shape + assert result_delta_t.shape == expected_delta_t.shape + assert_allclose(result_msd, expected_msd, rtol=1e-5) + assert_allclose(result_delta_t, expected_delta_t, rtol=1e-5) diff --git a/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump b/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump deleted file mode 100644 index 14ed8ecddd..0000000000 --- a/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump +++ /dev/null @@ -1,264 +0,0 @@ -ITEM: TIMESTEP -1 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0355600153744795e+01 2.0355600153744795e+01 --2.0355600153744795e+01 2.0355600153744795e+01 --2.0355600153744795e+01 2.0355600153744795e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.615361 0.916658 0.977605 0 0 0 -2 1 1 0 0.631398 0.899396 0.979776 0 0 0 -3 1 1 0 0.648404 0.88913 0.992135 0 0 0 -4 1 1 0 0.63267 0.875729 0.982023 0 0 0 -5 1 1 0 0.626438 0.883425 0.00280166 0 0 1 -6 1 1 0 0.637453 0.886813 0.024039 0 0 1 -7 1 1 0 0.652249 0.886889 0.0430888 0 0 1 -8 1 1 0 0.672732 0.883924 0.0523325 0 0 1 -9 1 1 0 0.657811 0.894604 0.0691854 0 0 1 -10 1 1 0 0.65649 0.916462 0.0804671 0 0 1 -11 1 1 0 0.665957 0.901445 0.0962088 0 0 1 -12 1 1 0 0.68522 0.907309 0.106795 0 0 1 -13 1 1 0 0.673061 0.895647 0.12283 0 0 1 -14 1 1 0 0.677892 0.879177 0.106639 0 0 1 -15 1 1 0 0.658043 0.879484 0.0932177 0 0 1 -ITEM: TIMESTEP -2 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0355603615290111e+01 2.0355603615290111e+01 --2.0355603615290111e+01 2.0355603615290111e+01 --2.0355603615290111e+01 2.0355603615290111e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.615491 0.91664 0.977656 0 0 0 -2 1 1 0 0.631369 0.899354 0.979803 0 0 0 -3 1 1 0 0.648464 0.889402 0.991954 0 0 0 -4 1 1 0 0.632719 0.875717 0.982054 0 0 0 -5 1 1 0 0.62648 0.883378 0.0027113 0 0 1 -6 1 1 0 0.637437 0.886657 0.024367 0 0 1 -7 1 1 0 0.652365 0.886662 0.0430756 0 0 1 -8 1 1 0 0.672732 0.88379 0.0520738 0 0 1 -9 1 1 0 0.657792 0.894523 0.0692184 0 0 1 -10 1 1 0 0.65657 0.916546 0.08031 0 0 1 -11 1 1 0 0.665797 0.90159 0.0963197 0 0 1 -12 1 1 0 0.685232 0.907541 0.106812 0 0 1 -13 1 1 0 0.672891 0.895405 0.122929 0 0 1 -14 1 1 0 0.677881 0.879209 0.106594 0 0 1 -15 1 1 0 0.657968 0.879496 0.093186 0 0 1 -ITEM: TIMESTEP -4 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0355610545665090e+01 2.0355610545665090e+01 --2.0355610545665090e+01 2.0355610545665090e+01 --2.0355610545665090e+01 2.0355610545665090e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.615719 0.916574 0.977758 0 0 0 -2 1 1 0 0.631259 0.899327 0.979874 0 0 0 -3 1 1 0 0.648652 0.889988 0.991619 0 0 0 -4 1 1 0 0.63284 0.875581 0.982058 0 0 0 -5 1 1 0 0.626644 0.883295 0.00265416 0 0 1 -6 1 1 0 0.637401 0.886324 0.0249678 0 0 1 -7 1 1 0 0.652469 0.886219 0.0429842 0 0 1 -8 1 1 0 0.672776 0.883545 0.0517394 0 0 1 -9 1 1 0 0.657776 0.894369 0.0692668 0 0 1 -10 1 1 0 0.656727 0.916605 0.0799941 0 0 1 -11 1 1 0 0.665477 0.901964 0.0965097 0 0 1 -12 1 1 0 0.685271 0.908083 0.106952 0 0 1 -13 1 1 0 0.672591 0.894954 0.123069 0 0 1 -14 1 1 0 0.677802 0.879268 0.106524 0 0 1 -15 1 1 0 0.657972 0.879341 0.0930271 0 0 1 -ITEM: TIMESTEP -8 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0355624425159920e+01 2.0355624425159920e+01 --2.0355624425159920e+01 2.0355624425159920e+01 --2.0355624425159920e+01 2.0355624425159920e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.616006 0.916443 0.977892 0 0 0 -2 1 1 0 0.630818 0.899376 0.980077 0 0 0 -3 1 1 0 0.649256 0.891177 0.991051 0 0 0 -4 1 1 0 0.633264 0.874995 0.981907 0 0 0 -5 1 1 0 0.627256 0.883173 0.00305087 0 0 1 -6 1 1 0 0.637186 0.885571 0.0257625 0 0 1 -7 1 1 0 0.652234 0.88538 0.0426589 0 0 1 -8 1 1 0 0.673077 0.883186 0.0518193 0 0 1 -9 1 1 0 0.657855 0.894068 0.0692517 0 0 1 -10 1 1 0 0.657053 0.916208 0.0794189 0 0 1 -11 1 1 0 0.66495 0.90296 0.0968392 0 0 1 -12 1 1 0 0.685278 0.909178 0.107584 0 0 1 -13 1 1 0 0.672306 0.894367 0.122982 0 0 1 -14 1 1 0 0.677482 0.879313 0.106397 0 0 1 -15 1 1 0 0.658316 0.878697 0.0925012 0 0 1 -ITEM: TIMESTEP -16 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0355652203773612e+01 2.0355652203773612e+01 --2.0355652203773612e+01 2.0355652203773612e+01 --2.0355652203773612e+01 2.0355652203773612e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.615575 0.916953 0.977501 0 0 0 -2 1 1 0 0.629751 0.898727 0.981024 0 0 0 -3 1 1 0 0.650483 0.892872 0.98997 0 0 0 -4 1 1 0 0.635076 0.873978 0.98216 0 0 0 -5 1 1 0 0.629168 0.882789 0.0043001 0 0 1 -6 1 1 0 0.6358 0.883994 0.025552 0 0 1 -7 1 1 0 0.652013 0.88383 0.0426954 0 0 1 -8 1 1 0 0.673463 0.883026 0.0536994 0 0 1 -9 1 1 0 0.658396 0.893137 0.0686492 0 0 1 -10 1 1 0 0.657585 0.914034 0.0782405 0 0 1 -11 1 1 0 0.664795 0.904917 0.0981176 0 0 1 -12 1 1 0 0.684787 0.909811 0.108785 0 0 1 -13 1 1 0 0.672999 0.895003 0.12184 0 0 1 -14 1 1 0 0.67687 0.878746 0.105873 0 0 1 -15 1 1 0 0.658398 0.878321 0.0914959 0 0 1 -ITEM: TIMESTEP -32 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0355707886159603e+01 2.0355707886159603e+01 --2.0355707886159603e+01 2.0355707886159603e+01 --2.0355707886159603e+01 2.0355707886159603e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.613435 0.916559 0.976467 0 0 0 -2 1 1 0 0.627485 0.899059 0.984065 0 0 0 -3 1 1 0 0.650294 0.893892 0.988746 0 0 0 -4 1 1 0 0.640612 0.873145 0.983177 0 0 0 -5 1 1 0 0.631807 0.882126 0.00390726 0 0 1 -6 1 1 0 0.637315 0.885369 0.0274023 0 0 1 -7 1 1 0 0.653768 0.883342 0.0439789 0 0 1 -8 1 1 0 0.675085 0.881167 0.0545631 0 0 1 -9 1 1 0 0.656816 0.889778 0.0684146 0 0 1 -10 1 1 0 0.65784 0.911406 0.0779864 0 0 1 -11 1 1 0 0.66368 0.906193 0.0998673 0 0 1 -12 1 1 0 0.687786 0.909147 0.105335 0 0 1 -13 1 1 0 0.673776 0.8953 0.1212 0 0 1 -14 1 1 0 0.675965 0.87761 0.105024 0 0 1 -15 1 1 0 0.656485 0.880392 0.0909747 0 0 1 -ITEM: TIMESTEP -64 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0355819396722975e+01 2.0355819396722975e+01 --2.0355819396722975e+01 2.0355819396722975e+01 --2.0355819396722975e+01 2.0355819396722975e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.612397 0.915364 0.975077 0 0 0 -2 1 1 0 0.627017 0.899021 0.984177 0 0 0 -3 1 1 0 0.65009 0.894923 0.988037 0 0 0 -4 1 1 0 0.640029 0.873573 0.982576 0 0 0 -5 1 1 0 0.631138 0.882347 0.00388604 0 0 1 -6 1 1 0 0.642827 0.888427 0.0240709 0 0 1 -7 1 1 0 0.657126 0.889982 0.0429142 0 0 1 -8 1 1 0 0.677502 0.88062 0.0516138 0 0 1 -9 1 1 0 0.665198 0.890914 0.070222 0 0 1 -10 1 1 0 0.653378 0.909947 0.0800473 0 0 1 -11 1 1 0 0.664993 0.904892 0.100965 0 0 1 -12 1 1 0 0.687459 0.903302 0.102878 0 0 1 -13 1 1 0 0.678095 0.89323 0.121566 0 0 1 -14 1 1 0 0.678102 0.88105 0.10132 0 0 1 -15 1 1 0 0.655175 0.879363 0.094859 0 0 1 -ITEM: TIMESTEP -128 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0356045145307441e+01 2.0356045145307441e+01 --2.0356045145307441e+01 2.0356045145307441e+01 --2.0356045145307441e+01 2.0356045145307441e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.615243 0.919081 0.977376 0 0 0 -2 1 1 0 0.632321 0.905551 0.986006 0 0 0 -3 1 1 0 0.654431 0.894739 0.983651 0 0 0 -4 1 1 0 0.638793 0.87805 0.980686 0 0 0 -5 1 1 0 0.636785 0.885242 0.00369442 0 0 1 -6 1 1 0 0.649105 0.893731 0.0217439 0 0 1 -7 1 1 0 0.653512 0.891718 0.0464078 0 0 1 -8 1 1 0 0.675349 0.891617 0.0534082 0 0 1 -9 1 1 0 0.661515 0.894532 0.0724292 0 0 1 -10 1 1 0 0.652331 0.912173 0.084505 0 0 1 -11 1 1 0 0.66666 0.905874 0.102395 0 0 1 -12 1 1 0 0.689428 0.90439 0.10817 0 0 1 -13 1 1 0 0.675708 0.894913 0.123856 0 0 1 -14 1 1 0 0.678148 0.880247 0.105302 0 0 1 -15 1 1 0 0.657725 0.884598 0.0939046 0 0 1 -ITEM: TIMESTEP -256 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0356514719385785e+01 2.0356514719385785e+01 --2.0356514719385785e+01 2.0356514719385785e+01 --2.0356514719385785e+01 2.0356514719385785e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.619466 0.922681 0.970428 0 0 0 -2 1 1 0 0.631589 0.909615 0.984267 0 0 0 -3 1 1 0 0.65253 0.897326 0.988031 0 0 0 -4 1 1 0 0.642706 0.876486 0.988435 0 0 0 -5 1 1 0 0.636007 0.880319 0.0097077 0 0 1 -6 1 1 0 0.656444 0.894027 0.0127605 0 0 1 -7 1 1 0 0.657297 0.890755 0.0376228 0 0 1 -8 1 1 0 0.669476 0.889982 0.0567176 0 0 1 -9 1 1 0 0.647482 0.888321 0.0651679 0 0 1 -10 1 1 0 0.655117 0.907372 0.0795585 0 0 1 -11 1 1 0 0.672847 0.903298 0.0939032 0 0 1 -12 1 1 0 0.689449 0.902073 0.111466 0 0 1 -13 1 1 0 0.667796 0.89178 0.117445 0 0 1 -14 1 1 0 0.679951 0.877666 0.102567 0 0 1 -15 1 1 0 0.657944 0.880017 0.0954321 0 0 1 -ITEM: TIMESTEP -512 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0357512117776135e+01 2.0357512117776135e+01 --2.0357512117776135e+01 2.0357512117776135e+01 --2.0357512117776135e+01 2.0357512117776135e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.619846 0.917655 0.993467 0 0 0 -2 1 1 0 0.61705 0.896707 0.980912 0 0 0 -3 1 1 0 0.638851 0.889076 0.986676 0 0 0 -4 1 1 0 0.64121 0.8686 0.995096 0 0 0 -5 1 1 0 0.636671 0.883339 0.0126369 0 0 1 -6 1 1 0 0.659342 0.888701 0.00398138 0 0 1 -7 1 1 0 0.656349 0.888655 0.02843 0 0 1 -8 1 1 0 0.666885 0.888935 0.0487139 0 0 1 -9 1 1 0 0.646898 0.878177 0.0614737 0 0 1 -10 1 1 0 0.655031 0.898687 0.0709038 0 0 1 -11 1 1 0 0.665319 0.901307 0.0916725 0 0 1 -12 1 1 0 0.680209 0.904584 0.110239 0 0 1 -13 1 1 0 0.666398 0.884577 0.111957 0 0 1 -14 1 1 0 0.670707 0.868407 0.0947354 0 0 1 -15 1 1 0 0.652102 0.879773 0.0878579 0 0 1 -ITEM: TIMESTEP -1024 -ITEM: NUMBER OF ATOMS -15 -ITEM: BOX BOUNDS pp pp pp --2.0359510373749348e+01 2.0359510373749348e+01 --2.0359510373749348e+01 2.0359510373749348e+01 --2.0359510373749348e+01 2.0359510373749348e+01 -ITEM: ATOMS id mol type q xs ys zs ix iy iz -1 1 1 0 0.628446 0.918265 0.989162 0 0 0 -2 1 1 0 0.614481 0.90596 0.973887 0 0 0 -3 1 1 0 0.623009 0.883136 0.973127 0 0 0 -4 1 1 0 0.62809 0.869983 0.991524 0 0 0 -5 1 1 0 0.638659 0.880527 0.00929481 0 0 1 -6 1 1 0 0.660935 0.883049 0.0188596 0 0 1 -7 1 1 0 0.662719 0.862462 0.0298895 0 0 1 -8 1 1 0 0.664646 0.86312 0.0535608 0 0 1 -9 1 1 0 0.652297 0.856703 0.0729134 0 0 1 -10 1 1 0 0.65923 0.877509 0.0843681 0 0 1 -11 1 1 0 0.679945 0.883899 0.0917732 0 0 1 -12 1 1 0 0.664801 0.89156 0.109159 0 0 1 -13 1 1 0 0.675896 0.873331 0.119055 0 0 1 -14 1 1 0 0.660676 0.86256 0.105118 0 0 1 -15 1 1 0 0.647792 0.877426 0.119059 0 0 1 diff --git a/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump.bz2 b/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..eb508142fdd380c4939039742f7704eafd73b6af GIT binary patch literal 2210 zcmV;T2wnF=T4*^jL0KkKStYmK82}M&-+&+xKns8HHzVFa1}5xqU<=;+?v(Z>HuPB#58C$^-vQNAizu$L8C?plmQA+=``{*j6+XHsP!Cli2?)&5FkK-0tI%= z$;M>hnUMuPN<}Diq>4fcN+}|eARa6O^?iR&HrsO$FaZ!B(i*$Os#nuwT2fp6+hn0Q zwIE!J(R)KG)r`jWEEg{HUE!CTLgN#vv`}ng%q7Tj_HbaAyR@1A*?=NvvVs%-Sx-Fe+Ep8=S zI1X;vS9M9O#I7$+S3rOuR^XRia#)pC_0I*EjAmtQ;?yRrWi3x!Uhd6_j9T?=?abO? z#pcp#wCK=eT;Og>k#0uP7!5(BnW?X+*5P|QORHzI9Hl|XqR6{*k`*T|L2}zjT$~nm z%ePZ&&;&#{hyns42^CPu>1+}KE(N$S3ZetyGYo;uiPR+^ke5lt83njSKqXC?t>eT= z1B}vUg&NVJAqupOAz5)KfO;w9r~0H6`Kc7~Q|_mAKPq~u<|%bPs&-SlniQyjd=L*X z9}xhGh`-W`0qjyLiu--Tu|&jAP|octLa7ehW1DS;xx& zY8e!FvSx|7&bP=&MMmI&0QeD$L|=q7&K3Z6IEth!*n||%Iq|)uJkN5%HUpL%c%d8< zY!7YgFDr6oM;2V0AUk!tiwvQMq!uDU-%;&PO$agWs*N1qknmHvs;fLHW(Zs>NRrHW zfQ~5$ikcKj8VN93igYS5PYNka9Q8Wl^18NB1ihel;IX6q|TDCD}_~8&v zRN9;%6jP%ay=__<8g8;X7!6CQM?=p!-glZ?fwhaREqm)cV}&}P@NNz9u6J3xk38Ra zm{B5gNQD_MZ#EzsJBz|TGblpp*nrZgfNX#ch><>=tDzVpGoI#b0j4<71tn#A?e?6L zi?cfLkpvv1)&oIy_2LqEcAT*iB5Lu z5cY3DB1v0F+cU8fI&R;}wnP`7CyMy`!JVEZj7prT^*=h^)7G%kC{(&mo|fje=Xs=; z2suY8@jJ94P1R_HEOD1xGgWdoGcTJ{o41-#MC)1TfMNo?_G$9ttVYk0u-8nfiSB5y zTo$V**F8*o+7}KUvou2CcrOsrS2uc&W2_=IuGA$bd%yt_L`e}uM#L$R5+dJa=pdO} zjO&_ukb*ElxQn|YD~8tDM^|W$joL{peLJCPHM4OWSBmw~5$kOD6P{8k{C22OHP0T- z)c7ZTYJ+}=9S|fl&cl@!Ds31Z+bzXV&OJUT8*$(H`)JQ#xy@ z27F))Nt`Vp*kUfSnPM!Ybt@QQZDgzGOk*KXsO;Rj~~cA*>?p@BBkIB?@D zg$>mwcIk)Covdt~tPRmll;-7aI=mS}C5`MDHIs!lG~+cKjki(JvXY!;!%qr~u=kfY@0!K%6WU7A+o^IBehwh0}3EB0{$QZ@%eds*P)n~^VFZqq8*ef=1&_R9v;;Q zMcWaU@K}Qa$g>RfXIx5A6N)6j43Y)f86(+^s)j`;lLEvT!zQ*|a#>4*+tS~z@?=Ee zWJZ_*yo4;6=BO#`UTm!1*{pzMmqV&YmqeKWsrQ;IOvsz$)Vl}HwGpK4}I4P|Mb8FxWah!P6|a>! zViGxm7D-2GbtSu_pH5)Xw6fA7C2>?D^^DEQ1VgzCY=}x0ia0ae$-dq3th(D0RORrR z5+~UrXRKqMdNB8*0oU!##Bj#Sp?z+X)@L9jpK0xuJID|$JWdzi4EhwT0jeIhlDSI-I zr!2DI2P&m}px?ufGs3izR6~5U#e7tRnwv^QmMfcA+Z3afE)Bt}CrRfu_f<#!CPCb+Xv21q6(&@n!l8fwg7Yd9zbfQ_6s z#Z3T+x*|Z)2h}D$*}iU^H9dc*5eMuk6oQ_reU%@gmQ(DdRQ3X&P*bv^`RH~Iz!APW2@}(4_kx$UOk}1N3fi1r1$R4HsFaQ7m literal 0 HcmV?d00001 diff --git a/testsuite/MDAnalysisTests/datafiles.py b/testsuite/MDAnalysisTests/datafiles.py index e32807058f..09b9578d68 100644 --- a/testsuite/MDAnalysisTests/datafiles.py +++ b/testsuite/MDAnalysisTests/datafiles.py @@ -273,6 +273,7 @@ "LAMMPSDUMP_chain2", # Lammps dump file with chain reader "LAMMPS_chain", # Lammps data file with chain reader "LAMMPSDUMP_additional_columns", # lammpsdump file with additional data (an additional charge column) + "LAMMPSDUMP_non_linear", # lammpsdump file to test calculating non-linear msd method "unordered_res", # pdb file with resids non sequential "GMS_ASYMOPT", # GAMESS C1 optimization "GMS_SYMOPT", # GAMESS D4h optimization @@ -389,7 +390,6 @@ "SURFACE_PDB", # 111 FCC lattice topology for NSGrid bug #2345 "SURFACE_TRR", # full precision coordinates for NSGrid bug #2345 "DSSP", # DSSP test suite - "LAMMPSDUMP_non_linear" ] from importlib import resources @@ -784,6 +784,7 @@ LAMMPSDUMP_additional_columns = ( _data_ref / "lammps/additional_columns.lammpstrj" ).as_posix() +LAMMPSDUMP_non_linear = (_data_ref / "custom_non_linear/test_non_linear.dump.bz2").as_posix() unordered_res = (_data_ref / "unordered_res.pdb").as_posix() @@ -907,7 +908,6 @@ SURFACE_PDB = (_data_ref / "surface.pdb.bz2").as_posix() SURFACE_TRR = (_data_ref / "surface.trr").as_posix() -LAMMPSDUMP_non_linear = (_data_ref / "custom_non_linear/test_non_linear.dump").as_posix() # DSSP testing: from https://github.com/ShintaroMinami/PyDSSP DSSP = (_data_ref / "dssp").as_posix() From 2bbdffb2d5915280c2e00def70ed420e9fe34f6e Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Mon, 28 Jul 2025 16:09:41 -0400 Subject: [PATCH 11/26] ran black 24.4.2 --- package/MDAnalysis/analysis/msd.py | 32 +++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index cd1ed618aa..c7d02ad114 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -319,7 +319,13 @@ class EinsteinMSD(AnalysisBase): """ def __init__( - self, u, select="all", msd_type="xyz", fft=True, non_linear=False, **kwargs + self, + u, + select="all", + msd_type="xyz", + fft=True, + non_linear=False, + **kwargs, ): r""" Parameters @@ -340,7 +346,9 @@ def __init__( non-linearly dumped. To use this set `fft=False`. """ if isinstance(u, groups.UpdatingAtomGroup): - raise TypeError("UpdatingAtomGroups are not valid for MSD " "computation") + raise TypeError( + "UpdatingAtomGroups are not valid for MSD " "computation" + ) super(EinsteinMSD, self).__init__(u.universe.trajectory, **kwargs) @@ -364,8 +372,12 @@ def __init__( def _prepare(self): # self.n_frames only available here # these need to be zeroed prior to each run() call - self.results.msds_by_particle = np.zeros((self.n_frames, self.n_particles)) - self._position_array = np.zeros((self.n_frames, self.n_particles, self.dim_fac)) + self.results.msds_by_particle = np.zeros( + (self.n_frames, self.n_particles) + ) + self._position_array = np.zeros( + (self.n_frames, self.n_particles, self.dim_fac) + ) # self.results.timeseries not set here def _parse_msd_type(self): @@ -396,7 +408,9 @@ def _single_frame(self): r"""Constructs array of positions for MSD calculation.""" # shape of position array set here, use span in last dimension # from this point on - self._position_array[self._frame_index] = self.ag.positions[:, self._dim] + self._position_array[self._frame_index] = self.ag.positions[ + :, self._dim + ] def _conclude(self): if self.non_linear: @@ -436,7 +450,9 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. positions = self._position_array.astype(np.float64) for n in tqdm(range(self.n_particles)): - self.results.msds_by_particle[:, n] = tidynamics.msd(positions[:, n, :]) + self.results.msds_by_particle[:, n] = tidynamics.msd( + positions[:, n, :] + ) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) def _conclude_non_linear(self): @@ -475,4 +491,6 @@ def _conclude_non_linear(self): avg_msds.append(avg_msd) self.results.timeseries = np.array(avg_msds, dtype=np.float64) - self.results.delta_t_values = np.array(delta_t_values, dtype=np.float64) + self.results.delta_t_values = np.array( + delta_t_values, dtype=np.float64 + ) From ee764b7c4ea4f0168e70a0dcfe07d6e9f2f4f624 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Mon, 28 Jul 2025 16:12:48 -0400 Subject: [PATCH 12/26] ran black on datafiles.py --- testsuite/MDAnalysisTests/datafiles.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testsuite/MDAnalysisTests/datafiles.py b/testsuite/MDAnalysisTests/datafiles.py index 09b9578d68..1ae92f903b 100644 --- a/testsuite/MDAnalysisTests/datafiles.py +++ b/testsuite/MDAnalysisTests/datafiles.py @@ -784,7 +784,9 @@ LAMMPSDUMP_additional_columns = ( _data_ref / "lammps/additional_columns.lammpstrj" ).as_posix() -LAMMPSDUMP_non_linear = (_data_ref / "custom_non_linear/test_non_linear.dump.bz2").as_posix() +LAMMPSDUMP_non_linear = ( + _data_ref / "custom_non_linear/test_non_linear.dump.bz2" +).as_posix() unordered_res = (_data_ref / "unordered_res.pdb").as_posix() From 0f50810a334e235bff371a0538c8b7776c01cb11 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Mon, 28 Jul 2025 17:08:01 -0400 Subject: [PATCH 13/26] cleanup - removed docs and edited formatting --- package/MDAnalysis/analysis/msd.py | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index c7d02ad114..cc38f6a13e 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -103,8 +103,7 @@ msd = MSD.results.timeseries -Visual inspection of the MSD is important, so let's take a look at it with a - simple plot. +Visual inspection of the MSD is important, so let's take a look at it with a simple plot. .. code-block:: python @@ -327,24 +326,6 @@ def __init__( non_linear=False, **kwargs, ): - r""" - Parameters - ---------- - u : Universe or AtomGroup - An MDAnalysis :class:`Universe` or :class:`AtomGroup`. - select : str - A selection string. Defaults to "all" in which case - all atoms are selected. - msd_type : {'xyz', 'xy', 'yz', 'xz', 'x', 'y', 'z'} - Desired dimensions to be included in the MSD. - fft : bool - If ``True``, uses a fast FFT based algorithm for computation of - the MSD. Otherwise, use the simple "windowed" algorithm. - The tidynamics package is required for `fft=True`. - non_linear : bool - If ``True``, calculates MSD for trajectory where frames are - non-linearly dumped. To use this set `fft=False`. - """ if isinstance(u, groups.UpdatingAtomGroup): raise TypeError( "UpdatingAtomGroups are not valid for MSD " "computation" From 7b16b9fda096c804556aa1bc083e1511c69e2df1 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Mon, 28 Jul 2025 22:05:03 -0400 Subject: [PATCH 14/26] added results.msds_by_particle for non_linear method --- package/MDAnalysis/analysis/msd.py | 25 +- .../MDAnalysisTests/analysis/test_msd.py | 1043 +++++++++++++++++ 2 files changed, 1058 insertions(+), 10 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index cc38f6a13e..182072cc06 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -446,32 +446,37 @@ def _conclude_non_linear(self): msd_dict = collections.defaultdict( list ) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} + msds_by_particle_dict = collections.defaultdict(list) + # TODO: optimize the code # Looping over all the frames as if the referenced gets shifted frame to frame for i in range(n_frames): for j in range(i + 1, n_frames): delta_t = dump_times[j] - dump_times[i] - # Compute displacement and squared displacement disp = positions[j] - positions[i] squared_disp = np.sum(disp**2, axis=1) msd = np.mean(squared_disp) - # Store MSD under corresponding Δt msd_dict[delta_t].append(msd) + msds_by_particle_dict[delta_t].append(squared_disp) msd_dict[0] = [0] + msds_by_particle_dict[0.0] = [np.zeros(n_atoms)] - # Prepare averaged results - delta_t_values = [] - avg_msds = [] - for delta_t in sorted(msd_dict.keys()): - msd_list = msd_dict[delta_t] - avg_msd = np.mean(msd_list) - delta_t_values.append(delta_t) - avg_msds.append(avg_msd) + # For each delta_t, stacked all squared_disp arrays and averaging over axis=0 (time origins) + delta_t_values = sorted(msd_dict.keys()) + avg_msds = [np.mean(msd_dict[dt]) for dt in delta_t_values] + msds_by_particle_array = np.zeros((len(delta_t_values), n_atoms)) + for idx, dt in enumerate(delta_t_values): + # Stack list of arrays like -- (n_time_origins, n_atoms) + arr = np.vstack(msds_by_particle_dict[dt]) + msds_by_particle_array[idx, :] = np.mean(arr, axis=0) self.results.timeseries = np.array(avg_msds, dtype=np.float64) self.results.delta_t_values = np.array( delta_t_values, dtype=np.float64 ) + self.results.msds_by_particle = np.array( + msds_by_particle_array, dtype=np.float64 + ) diff --git a/testsuite/MDAnalysisTests/analysis/test_msd.py b/testsuite/MDAnalysisTests/analysis/test_msd.py index 35b9617fc7..0e8c9dad53 100644 --- a/testsuite/MDAnalysisTests/analysis/test_msd.py +++ b/testsuite/MDAnalysisTests/analysis/test_msd.py @@ -304,6 +304,7 @@ def test_all_msd_types(self, u_nonlinear, dim, dim_factor): msd.run() result_msd = msd.results.timeseries result_delta_t = msd.results.delta_t_values + result_msd_per_particle = msd.results.msds_by_particle expected_results_msd = { "xyz": np.array( [ @@ -792,14 +793,1056 @@ def test_all_msd_types(self, u_nonlinear, dim, dim_factor): assert_allclose(result_msd, expected_msd, rtol=1e-5) assert_allclose(result_delta_t, expected_delta_t, rtol=1e-5) + def test_msds_per_particle(self, u_nonlinear): + msd = MSD(u_nonlinear, select="all", msd_type="xyz", non_linear=True) + msd.run() + result_msd_per_particle = msd.results.msds_by_particle + expected_msd_per_particle = np.array( + [ + [ + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + 0.00000000e00, + ], + [ + 3.29547038e-05, + 5.48541720e-06, + 1.82997159e-04, + 5.86525130e-06, + 2.00792165e-05, + 2.19020443e-04, + 1.07918182e-04, + 1.40443055e-04, + 1.31939923e-05, + 6.32751799e-05, + 9.77258060e-05, + 9.01585336e-05, + 1.60915810e-04, + 5.26360600e-06, + 1.11690897e-05, + ], + [ + 1.11020650e-04, + 2.95432983e-05, + 8.14488783e-04, + 5.48629032e-05, + 6.14942110e-05, + 7.83963249e-04, + 3.56422974e-04, + 2.87535921e-04, + 4.34042777e-05, + 2.12105602e-04, + 4.61613050e-04, + 5.22839753e-04, + 5.17809243e-04, + 2.41769339e-05, + 8.13590741e-05, + ], + [ + 2.63813577e-04, + 5.56142040e-05, + 1.76485543e-03, + 8.62745947e-05, + 1.34402031e-04, + 1.83009465e-03, + 8.41153775e-04, + 8.22875827e-04, + 1.03974497e-04, + 4.98132900e-04, + 9.78943150e-04, + 1.04020679e-03, + 1.25445600e-03, + 4.90201928e-05, + 1.01787577e-04, + ], + [ + 1.95492961e-04, + 3.94420946e-04, + 3.48568599e-03, + 9.03695662e-04, + 9.07771875e-04, + 2.06086619e-03, + 1.42940438e-03, + 3.74201296e-04, + 1.60095136e-04, + 9.84441944e-04, + 2.28692875e-03, + 2.65435437e-03, + 7.15362199e-04, + 1.98882743e-04, + 1.34003449e-03, + ], + [ + 5.98546074e-04, + 6.27848276e-04, + 7.62002755e-03, + 1.39002870e-03, + 1.26137879e-03, + 5.28286425e-03, + 3.03226555e-03, + 9.07422454e-04, + 3.49758022e-04, + 1.89043468e-03, + 4.75146946e-03, + 5.44308133e-03, + 2.35025800e-03, + 3.44575110e-04, + 2.03212918e-03, + ], + [ + 9.06110930e-04, + 7.07433705e-04, + 1.01047072e-02, + 1.49807159e-03, + 1.31984901e-03, + 7.59302815e-03, + 4.07066270e-03, + 1.53285325e-03, + 4.83971744e-04, + 2.45190217e-03, + 6.14914359e-03, + 6.84060395e-03, + 3.68796213e-03, + 4.04686522e-04, + 1.99590813e-03, + ], + [ + 9.90922374e-04, + 4.06796762e-03, + 9.20377615e-03, + 7.26651738e-03, + 8.90031873e-03, + 7.36212283e-03, + 4.05492755e-03, + 6.15373092e-03, + 2.51891323e-03, + 1.05901041e-02, + 9.11065105e-03, + 3.45879569e-03, + 3.63240972e-03, + 1.60079393e-03, + 1.91596798e-03, + ], + [ + 3.81979640e-04, + 6.55204030e-03, + 2.38731745e-02, + 1.25663249e-02, + 1.54929261e-02, + 1.37795487e-02, + 9.91460410e-03, + 7.60385905e-03, + 3.77585457e-03, + 1.72474579e-02, + 1.95383917e-02, + 1.09266188e-02, + 2.78197088e-03, + 2.57883530e-03, + 5.89875714e-03, + ], + [ + 2.16478569e-04, + 7.45433617e-03, + 3.32705393e-02, + 1.42417599e-02, + 1.67581842e-02, + 1.84839473e-02, + 1.37015482e-02, + 6.23839337e-03, + 4.31364206e-03, + 1.92358004e-02, + 2.54031426e-02, + 1.53514380e-02, + 2.24383608e-03, + 2.89311686e-03, + 7.31224184e-03, + ], + [ + 2.42450827e-04, + 7.81072883e-03, + 3.81783636e-02, + 1.47116919e-02, + 1.67693081e-02, + 2.14513914e-02, + 1.58174735e-02, + 5.32206634e-03, + 4.59639255e-03, + 1.99454904e-02, + 2.82963822e-02, + 1.72861295e-02, + 2.30458753e-03, + 2.99275187e-03, + 7.34524157e-03, + ], + [ + 9.57952908e-03, + 2.40431962e-02, + 4.26129746e-03, + 5.37208999e-02, + 1.25439480e-02, + 1.26534763e-02, + 8.24814401e-03, + 1.13230807e-02, + 2.28689772e-02, + 1.16296926e-02, + 9.84728085e-03, + 3.53700031e-02, + 1.83373150e-03, + 4.66237709e-03, + 1.36276561e-02, + ], + [ + 1.42789247e-02, + 4.49616170e-02, + 2.28301928e-02, + 9.79386640e-02, + 3.74167756e-02, + 4.56202170e-03, + 1.36675322e-02, + 2.59318735e-02, + 3.33500859e-02, + 4.25564267e-02, + 3.52603202e-02, + 1.88316717e-02, + 1.03127103e-02, + 1.16787130e-02, + 1.41711717e-02, + ], + [ + 1.13383621e-02, + 5.28644852e-02, + 4.34575366e-02, + 1.12140195e-01, + 4.91246783e-02, + 1.13449105e-02, + 1.81233278e-02, + 3.14404287e-02, + 3.75384545e-02, + 5.34189770e-02, + 5.37724765e-02, + 1.67492262e-02, + 8.32656867e-03, + 1.37936572e-02, + 1.24532467e-02, + ], + [ + 9.28934888e-03, + 5.52802469e-02, + 5.60822376e-02, + 1.16430995e-01, + 5.20844630e-02, + 1.80384823e-02, + 2.28397570e-02, + 3.08590754e-02, + 3.98280457e-02, + 5.52886446e-02, + 6.35076370e-02, + 1.87768302e-02, + 6.26772415e-03, + 1.43155756e-02, + 1.30501318e-02, + ], + [ + 8.24139445e-03, + 5.60812412e-02, + 6.26075889e-02, + 1.17942565e-01, + 5.26841868e-02, + 2.22288270e-02, + 2.59414039e-02, + 3.00244323e-02, + 4.10809178e-02, + 5.54656041e-02, + 6.82505538e-02, + 2.01289939e-02, + 5.43876016e-03, + 1.44529277e-02, + 1.36953083e-02, + ], + [ + 7.26572104e-03, + 3.78830548e-04, + 2.66685334e-03, + 1.44832527e-03, + 8.15123480e-04, + 8.44108736e-02, + 9.38697999e-02, + 2.46033816e-02, + 1.24227774e-01, + 4.34564373e-02, + 7.66600866e-03, + 6.66236940e-02, + 3.82861185e-02, + 5.00133501e-02, + 2.95946204e-02, + ], + [ + 3.04077466e-02, + 2.90646969e-02, + 1.34089199e-02, + 4.13755194e-02, + 7.07925708e-03, + 1.18413483e-01, + 1.06534420e-01, + 4.38493195e-02, + 8.91309851e-02, + 6.21699068e-02, + 1.35562900e-02, + 1.39625085e-01, + 4.84668860e-02, + 4.57241120e-02, + 3.77554297e-02, + ], + [ + 3.63440618e-02, + 5.20567581e-02, + 3.95215313e-02, + 8.01595816e-02, + 2.73821643e-02, + 7.13045214e-02, + 7.52595929e-02, + 4.34848262e-02, + 1.07567023e-01, + 8.76068082e-02, + 3.45693293e-02, + 1.01547952e-01, + 6.11471364e-02, + 4.83617131e-02, + 2.62611499e-02, + ], + [ + 3.23117802e-02, + 6.07097117e-02, + 6.51664345e-02, + 9.29985226e-02, + 3.76280686e-02, + 5.77555913e-02, + 5.97845004e-02, + 5.12750264e-02, + 1.12746984e-01, + 9.16156305e-02, + 4.77102418e-02, + 7.31038407e-02, + 5.89875917e-02, + 5.02876992e-02, + 1.84581297e-02, + ], + [ + 2.92695918e-02, + 6.33243799e-02, + 8.04641860e-02, + 9.68530395e-02, + 4.01675329e-02, + 5.37861708e-02, + 5.62332763e-02, + 5.47512690e-02, + 1.14313454e-01, + 8.87141741e-02, + 5.51365068e-02, + 6.34530888e-02, + 5.58837453e-02, + 5.17867676e-02, + 1.75140888e-02, + ], + [ + 2.76117514e-02, + 6.41844460e-02, + 8.83072363e-02, + 9.81920130e-02, + 4.06447266e-02, + 5.24859771e-02, + 5.56812634e-02, + 5.66825173e-02, + 1.14935578e-01, + 8.62270814e-02, + 5.89627860e-02, + 6.01585961e-02, + 5.43943312e-02, + 5.27664145e-02, + 1.80339359e-02, + ], + [ + 4.55190605e-02, + 1.23504744e-01, + 6.31111118e-02, + 4.17455815e-02, + 6.71836578e-02, + 1.21421180e-01, + 4.68796988e-02, + 2.13966409e-01, + 5.23277565e-02, + 4.31326111e-02, + 9.74844111e-03, + 5.50657852e-02, + 2.28663271e-02, + 2.74040840e-02, + 5.80642113e-02, + ], + [ + 1.77127374e-02, + 1.15823873e-01, + 7.24949145e-02, + 5.57014738e-02, + 5.77815115e-02, + 4.00573632e-01, + 1.26863097e-01, + 1.84102374e-01, + 1.01559988e-01, + 1.21625711e-01, + 2.57286919e-02, + 5.51329473e-02, + 1.83150224e-02, + 1.99033312e-02, + 4.65919405e-02, + ], + [ + 7.87452796e-03, + 1.30542354e-01, + 9.76530467e-02, + 5.44756028e-02, + 1.07494350e-01, + 4.76297096e-01, + 1.30635730e-01, + 1.29260977e-01, + 4.35271580e-02, + 1.16218722e-01, + 3.80001051e-02, + 8.48773590e-02, + 1.91909411e-02, + 7.19048976e-03, + 7.62703155e-02, + ], + [ + 1.30890397e-02, + 1.26521264e-01, + 1.56178831e-01, + 6.92059728e-02, + 1.59238430e-01, + 3.74156481e-01, + 9.34240399e-02, + 1.31599576e-01, + 3.97558461e-02, + 1.06259429e-01, + 7.07275694e-02, + 6.70161003e-02, + 2.13083230e-02, + 4.26700552e-03, + 6.21278092e-02, + ], + [ + 1.12121919e-02, + 1.29750834e-01, + 1.98096468e-01, + 7.25404134e-02, + 1.79567170e-01, + 3.36764030e-01, + 7.21105243e-02, + 1.24657417e-01, + 4.02441055e-02, + 9.76995542e-02, + 8.58065894e-02, + 5.37411193e-02, + 1.74258020e-02, + 4.33662320e-03, + 4.77155764e-02, + ], + [ + 1.03108396e-02, + 1.30292806e-01, + 2.20632668e-01, + 7.38579068e-02, + 1.84430439e-01, + 3.21562339e-01, + 6.36867632e-02, + 1.16896847e-01, + 4.05065880e-02, + 9.00290369e-02, + 9.35966376e-02, + 4.87967467e-02, + 1.52111116e-02, + 4.74256226e-03, + 4.46176945e-02, + ], + [ + 1.00592664e-02, + 1.29907989e-01, + 2.31809837e-01, + 7.46272090e-02, + 1.85303272e-01, + 3.14663344e-01, + 6.02779135e-02, + 1.12402415e-01, + 4.06291999e-02, + 8.55696231e-02, + 9.75423195e-02, + 4.67323443e-02, + 1.44511090e-02, + 5.04185116e-03, + 4.48151347e-02, + ], + [ + 1.31030153e-01, + 3.34567995e-02, + 4.94929071e-02, + 1.30020064e-01, + 1.00758336e-01, + 2.23511078e-01, + 1.53074901e-01, + 7.92003807e-02, + 4.75530940e-01, + 9.11369062e-02, + 1.93861038e-01, + 2.68156812e-02, + 1.86812581e-01, + 2.85957388e-02, + 3.83389544e-02, + ], + [ + 2.08690899e-01, + 2.22975564e-01, + 2.01470834e-02, + 8.46321639e-02, + 1.02934983e-01, + 5.73348566e-01, + 4.72739914e-02, + 2.95948289e-01, + 5.70657575e-01, + 1.61901615e-02, + 1.89428914e-01, + 1.31983466e-01, + 2.05563366e-01, + 2.70351174e-02, + 1.44732501e-02, + ], + [ + 1.83727647e-01, + 2.15285427e-01, + 2.95229664e-02, + 7.35485119e-02, + 9.11102616e-02, + 1.08956321e00, + 1.80128030e-01, + 1.89540307e-01, + 1.63483965e-01, + 4.23285485e-02, + 2.12547660e-01, + 1.49284235e-01, + 1.01318334e-01, + 3.67877221e-02, + 3.72032659e-02, + ], + [ + 1.62696106e-01, + 2.22651521e-01, + 4.68729804e-02, + 1.75213126e-01, + 1.37109099e-01, + 1.14878177e00, + 1.70241994e-01, + 1.22589894e-01, + 2.52989602e-01, + 8.49382109e-02, + 1.41906248e-01, + 1.46673198e-01, + 9.22477204e-02, + 3.58142677e-02, + 3.13827178e-02, + ], + [ + 1.76945602e-01, + 2.06974203e-01, + 9.67079167e-02, + 2.25356711e-01, + 2.15244723e-01, + 1.01736314e00, + 1.33952431e-01, + 1.38972351e-01, + 2.57512694e-01, + 1.33546320e-01, + 1.19004732e-01, + 1.37112426e-01, + 9.38492970e-02, + 3.86824317e-02, + 1.78200142e-02, + ], + [ + 1.74459726e-01, + 2.10759539e-01, + 1.36906376e-01, + 2.33344971e-01, + 2.43938160e-01, + 9.50278264e-01, + 1.21714452e-01, + 1.28965883e-01, + 2.60797540e-01, + 1.43691799e-01, + 1.05566832e-01, + 1.22476748e-01, + 1.05252358e-01, + 3.75688869e-02, + 1.07003001e-02, + ], + [ + 1.73637650e-01, + 2.10793205e-01, + 1.58467571e-01, + 2.37048831e-01, + 2.48592263e-01, + 9.15971117e-01, + 1.18626835e-01, + 1.17965100e-01, + 2.63760533e-01, + 1.41710643e-01, + 9.82716860e-02, + 1.14969218e-01, + 1.12527771e-01, + 3.76243294e-02, + 9.12505777e-03, + ], + [ + 1.73830044e-01, + 2.09755401e-01, + 1.68991063e-01, + 2.39327940e-01, + 2.48315000e-01, + 8.98760969e-01, + 1.17768543e-01, + 1.11329969e-01, + 2.65614224e-01, + 1.39234806e-01, + 9.45818872e-02, + 1.11335212e-01, + 1.16589571e-01, + 3.79905707e-02, + 8.91514683e-03, + ], + [ + 9.26454066e-01, + 6.38855875e-01, + 4.21319358e-01, + 1.79943843e-01, + 3.11304484e-02, + 1.87329255e-01, + 1.47447593e-01, + 1.17698910e-01, + 1.91043994e-01, + 2.46418008e-01, + 1.06673877e-01, + 1.53158258e-01, + 1.36744591e-01, + 3.80844184e-01, + 1.49904431e-01, + ], + [ + 4.74179240e-01, + 5.50400254e-01, + 4.65655469e-01, + 5.04632657e-01, + 1.39034165e-01, + 7.37636338e-01, + 5.62117094e-01, + 1.63353578e-01, + 9.85585836e-01, + 6.14565368e-01, + 2.24728007e-01, + 1.45824731e-01, + 5.47694577e-01, + 5.01761979e-01, + 1.47636846e-01, + ], + [ + 6.72023675e-01, + 1.85966247e-01, + 2.62832251e-01, + 3.06822210e-01, + 1.82682081e-01, + 1.12373842e00, + 3.48811862e-01, + 3.14729488e-01, + 9.38860768e-01, + 3.48026214e-01, + 1.61845874e-01, + 1.79069251e-01, + 4.95264141e-01, + 4.19238174e-01, + 9.52559806e-02, + ], + [ + 5.59203213e-01, + 2.00428494e-01, + 2.55943599e-01, + 2.73965972e-01, + 1.71434793e-01, + 1.73716901e00, + 4.59214613e-01, + 2.67625422e-01, + 4.56803123e-01, + 3.57023355e-01, + 1.52496550e-01, + 1.65939820e-01, + 4.13889405e-01, + 3.54383108e-01, + 4.63503606e-02, + ], + [ + 4.62597323e-01, + 2.69023630e-01, + 2.59106725e-01, + 3.93478778e-01, + 2.13155863e-01, + 1.73348644e00, + 4.08347091e-01, + 1.70164570e-01, + 6.63972600e-01, + 4.81783044e-01, + 8.84504943e-02, + 7.99825428e-02, + 4.05785779e-01, + 4.37286861e-01, + 8.89420795e-02, + ], + [ + 4.38002714e-01, + 3.21722017e-01, + 2.12020297e-01, + 4.66967165e-01, + 3.04185042e-01, + 1.62204964e00, + 3.82002047e-01, + 1.34069738e-01, + 7.05895905e-01, + 6.26057896e-01, + 4.75314559e-02, + 8.59783925e-02, + 4.09858051e-01, + 4.89499864e-01, + 9.91214509e-02, + ], + [ + 4.48419151e-01, + 3.42292557e-01, + 1.95040794e-01, + 4.84747110e-01, + 3.36990570e-01, + 1.54289979e00, + 3.85972715e-01, + 1.20567067e-01, + 7.19241938e-01, + 6.63920059e-01, + 3.83619000e-02, + 7.79704502e-02, + 4.37951102e-01, + 4.99977747e-01, + 9.89058194e-02, + ], + [ + 4.56856373e-01, + 3.47945833e-01, + 1.93607563e-01, + 4.91481873e-01, + 3.40634053e-01, + 1.49659900e00, + 3.88329643e-01, + 1.18825632e-01, + 7.26771488e-01, + 6.69251679e-01, + 3.52082740e-02, + 7.33447198e-02, + 4.54677321e-01, + 5.02418614e-01, + 1.01308440e-01, + ], + [ + 4.61455817e-01, + 3.49767272e-01, + 1.94792562e-01, + 4.94530826e-01, + 3.39094609e-01, + 1.47242744e00, + 3.89053698e-01, + 1.19460086e-01, + 7.30950347e-01, + 6.68851649e-01, + 3.37388871e-02, + 7.12586137e-02, + 4.63419021e-01, + 5.03295792e-01, + 1.03315279e-01, + ], + [ + 1.55385691e-01, + 2.34697953e-01, + 7.63966114e-01, + 3.03825998e-01, + 3.71506076e-02, + 4.24745755e-01, + 1.19922440e00, + 1.14060964e00, + 1.02442620e00, + 1.06795685e00, + 8.54842056e-01, + 6.64783658e-01, + 4.42815993e-01, + 3.97895039e-01, + 1.65740425e00, + ], + [ + 7.63425198e-01, + 6.66793673e-01, + 2.11022621e00, + 4.30060123e-01, + 1.36468186e-02, + 2.91657502e-01, + 1.45711098e00, + 1.22988218e00, + 1.77899207e00, + 1.52833714e00, + 7.05309099e-01, + 1.17732544e00, + 6.70122467e-01, + 9.84776901e-01, + 1.10709556e00, + ], + [ + 5.38195720e-01, + 7.50513454e-01, + 2.00575041e00, + 4.88752468e-01, + 9.39604234e-02, + 4.33617754e-01, + 1.99018819e00, + 1.50717324e00, + 2.47850173e00, + 2.04821863e00, + 1.26823956e00, + 1.25395122e00, + 7.92186959e-01, + 9.99608541e-01, + 1.29449637e00, + ], + [ + 7.95930368e-01, + 5.04414627e-01, + 1.77328308e00, + 3.87578991e-01, + 1.53210871e-01, + 6.43157467e-01, + 1.56569743e00, + 7.65311059e-01, + 2.19201079e00, + 1.81063295e00, + 1.23110073e00, + 1.12163190e00, + 6.56047003e-01, + 1.06814145e00, + 1.06972826e00, + ], + [ + 6.69417055e-01, + 5.18959856e-01, + 1.78786071e00, + 3.88519787e-01, + 1.35523899e-01, + 1.06701697e00, + 1.16882019e00, + 6.99191934e-01, + 1.85133116e00, + 1.94968684e00, + 1.36085853e00, + 1.38243802e00, + 7.97258569e-01, + 7.39410939e-01, + 1.44934461e00, + ], + [ + 5.24328863e-01, + 5.47006165e-01, + 1.83523282e00, + 2.53374803e-01, + 2.05757373e-01, + 1.13835556e00, + 1.20400992e00, + 7.62286366e-01, + 2.25817268e00, + 2.24988226e00, + 1.17011687e00, + 1.18412898e00, + 7.87787940e-01, + 8.44074318e-01, + 1.44944982e00, + ], + [ + 4.93969799e-01, + 5.66602817e-01, + 1.73937154e00, + 2.40650627e-01, + 2.99857097e-01, + 1.03750989e00, + 1.30688553e00, + 7.67488098e-01, + 2.35281508e00, + 2.50052150e00, + 1.01020887e00, + 1.18375116e00, + 7.63417659e-01, + 9.08951744e-01, + 1.35711084e00, + ], + [ + 5.10510237e-01, + 5.87663492e-01, + 1.69314196e00, + 2.38866570e-01, + 3.33667591e-01, + 1.01024798e00, + 1.37657881e00, + 7.83644541e-01, + 2.38828413e00, + 2.54491213e00, + 9.18408381e-01, + 1.12638011e00, + 8.01987300e-01, + 9.24668474e-01, + 1.30235187e00, + ], + [ + 5.23968337e-01, + 5.91753645e-01, + 1.68546560e00, + 2.39636505e-01, + 3.39810000e-01, + 9.99568909e-01, + 1.41895242e00, + 7.96981286e-01, + 2.40824620e00, + 2.53419306e00, + 8.78295300e-01, + 1.09610536e00, + 8.29086108e-01, + 9.26152093e-01, + 1.28937725e00, + ], + [ + 5.31575331e-01, + 5.91889580e-01, + 1.68629680e00, + 2.40149073e-01, + 3.39964249e-01, + 9.94394263e-01, + 1.44169989e00, + 8.04796912e-01, + 2.41905095e00, + 2.52202592e00, + 8.60755133e-01, + 1.08341982e00, + 8.43673187e-01, + 9.25220791e-01, + 1.28906196e00, + ], + ] + ) + assert result_msd_per_particle.shape == expected_msd_per_particle.shape + assert_allclose( + result_msd_per_particle, expected_msd_per_particle, rtol=1e-5 + ) + def test_start_stop_step(self, u_nonlinear): msd = MSD(u_nonlinear, select="all", msd_type="xyz", non_linear=True) msd.run(start=3, stop=9, step=2) result_msd = msd.results.timeseries result_delta_t = msd.results.delta_t_values + result_msd_per_particle = msd.results.msds_by_particle expected_msd = np.array([0.0, 0.02851658, 0.09466075, 0.09965838]) expected_delta_t = np.array([0.0, 24.0, 96.0, 120.0]) + expected_msd_per_particle = np.array( + [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ], + [ + 0.01427892, + 0.04496162, + 0.02283019, + 0.09793866, + 0.03741678, + 0.00456202, + 0.01366753, + 0.02593187, + 0.03335009, + 0.04255643, + 0.03526032, + 0.01883167, + 0.01031271, + 0.01167871, + 0.01417117, + ], + [ + 0.01771274, + 0.11582387, + 0.07249491, + 0.05570147, + 0.05778151, + 0.40057363, + 0.1268631, + 0.18410237, + 0.10155999, + 0.12162571, + 0.02572869, + 0.05513295, + 0.01831502, + 0.01990333, + 0.04659194, + ], + [ + 0.01308904, + 0.12652126, + 0.15617883, + 0.06920597, + 0.15923843, + 0.37415648, + 0.09342404, + 0.13159958, + 0.03975585, + 0.10625943, + 0.07072757, + 0.0670161, + 0.02130832, + 0.00426701, + 0.06212781, + ], + ] + ) assert result_msd.shape == expected_msd.shape assert result_delta_t.shape == expected_delta_t.shape + assert result_msd_per_particle.shape == expected_msd_per_particle.shape assert_allclose(result_msd, expected_msd, rtol=1e-5) assert_allclose(result_delta_t, expected_delta_t, rtol=1e-5) + assert_allclose( + result_msd_per_particle, expected_msd_per_particle, rtol=1e-5 + ) From 72b3dd3f5f8efae7b041aa02ee000373a317d2e2 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Tue, 29 Jul 2025 10:59:20 -0400 Subject: [PATCH 15/26] minor chancge - versionadded to versionchanged --- package/MDAnalysis/analysis/msd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 182072cc06..91534bc57e 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -312,7 +312,7 @@ class EinsteinMSD(AnalysisBase): .. versionadded:: 2.0.0 - .. versionadded:: 2.10.0 + .. versionchanged:: 2.10.0 Added ability to calculate MSD from samples that are not linearly spaced with the new `non_linear` keyword argument. """ From e36798447fae42bbfda81d6238dc7fa59edc57ad Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Wed, 30 Jul 2025 15:45:55 -0400 Subject: [PATCH 16/26] dtype removal and cleanup misplaced strings --- package/MDAnalysis/analysis/msd.py | 12 ++++-------- .../msd}/test_non_linear.dump.bz2 | Bin testsuite/MDAnalysisTests/datafiles.py | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) rename testsuite/MDAnalysisTests/data/{custom_non_linear => analysis/msd}/test_non_linear.dump.bz2 (100%) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 91534bc57e..0beb80db09 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -328,7 +328,7 @@ def __init__( ): if isinstance(u, groups.UpdatingAtomGroup): raise TypeError( - "UpdatingAtomGroups are not valid for MSD " "computation" + "UpdatingAtomGroups are not valid for MSD computation" ) super(EinsteinMSD, self).__init__(u.universe.trajectory, **kwargs) @@ -473,10 +473,6 @@ def _conclude_non_linear(self): arr = np.vstack(msds_by_particle_dict[dt]) msds_by_particle_array[idx, :] = np.mean(arr, axis=0) - self.results.timeseries = np.array(avg_msds, dtype=np.float64) - self.results.delta_t_values = np.array( - delta_t_values, dtype=np.float64 - ) - self.results.msds_by_particle = np.array( - msds_by_particle_array, dtype=np.float64 - ) + self.results.timeseries = np.array(avg_msds) + self.results.delta_t_values = np.array(delta_t_values) + self.results.msds_by_particle = msds_by_particle_array diff --git a/testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump.bz2 b/testsuite/MDAnalysisTests/data/analysis/msd/test_non_linear.dump.bz2 similarity index 100% rename from testsuite/MDAnalysisTests/data/custom_non_linear/test_non_linear.dump.bz2 rename to testsuite/MDAnalysisTests/data/analysis/msd/test_non_linear.dump.bz2 diff --git a/testsuite/MDAnalysisTests/datafiles.py b/testsuite/MDAnalysisTests/datafiles.py index 1ae92f903b..a38e6137cd 100644 --- a/testsuite/MDAnalysisTests/datafiles.py +++ b/testsuite/MDAnalysisTests/datafiles.py @@ -785,7 +785,7 @@ _data_ref / "lammps/additional_columns.lammpstrj" ).as_posix() LAMMPSDUMP_non_linear = ( - _data_ref / "custom_non_linear/test_non_linear.dump.bz2" + _data_ref / "analysis/msd/test_non_linear.dump.bz2" ).as_posix() unordered_res = (_data_ref / "unordered_res.pdb").as_posix() From 069bec5fce68b4d549dfa7cc6a0463cb988b9b9b Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Thu, 31 Jul 2025 14:44:23 -0400 Subject: [PATCH 17/26] Added entry to project.toml --- testsuite/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/testsuite/pyproject.toml b/testsuite/pyproject.toml index be1e349e4b..48bb5076f8 100644 --- a/testsuite/pyproject.toml +++ b/testsuite/pyproject.toml @@ -116,6 +116,7 @@ MDAnalysisTests = [ "data/*.mmtf", "data/*.mmtf.gz", "data/analysis/*", + "data/analysis/msd/*", "data/*.gsd", "data/windows/*", "data/*.itp", From ac4b4b22695a52e297c94be925316fba4f40466f Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Fri, 1 Aug 2025 10:16:53 -0400 Subject: [PATCH 18/26] Attribute definition edit for cases non_linear : bool --- package/MDAnalysis/analysis/msd.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 0beb80db09..43eef78411 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -294,12 +294,18 @@ class EinsteinMSD(AnalysisBase): dim_fac : int Dimensionality :math:`d` of the MSD. results.timeseries : :class:`numpy.ndarray` - The averaged MSD over all the particles with respect to lag-time. + The averaged MSD over all the particles with respect to constant lag-time or + unique Δt intervals. results.msds_by_particle : :class:`numpy.ndarray` - The MSD of each individual particle with respect to lag-time. + The MSD of each individual particle with respect to constant lag-time or + unique Δt intervals. + - for `non_linear=False`: a 2D array of shape (n_lagtimes, n_atoms) + - for `non_linear=True`: a 2D array of shape (n_delta_t_values, n_atoms) results.delta_t_values : :class:`numpy.ndarray` - Array of unique Δt (time differences) at which time-averaged MSD values are - computed. + - Array of unique Δt (time differences) at which time-averaged MSD values are + computed (for `non_linear=True`). + - For `non_linear=False` it is Null array. Time differences are same as the lag-times. + (To access: `lagtimes = np.arange(nframes)*timestep`) .. versionadded:: 2.10.0 From 3ceca5ceae17f0377031386b8da0e4a82984529b Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Fri, 1 Aug 2025 10:50:04 -0400 Subject: [PATCH 19/26] Indentation edit --- package/MDAnalysis/analysis/msd.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 43eef78411..22377c2f33 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -299,13 +299,13 @@ class EinsteinMSD(AnalysisBase): results.msds_by_particle : :class:`numpy.ndarray` The MSD of each individual particle with respect to constant lag-time or unique Δt intervals. - - for `non_linear=False`: a 2D array of shape (n_lagtimes, n_atoms) - - for `non_linear=True`: a 2D array of shape (n_delta_t_values, n_atoms) + for `non_linear=False`: a 2D array of shape (n_lagtimes, n_atoms) + for `non_linear=True`: a 2D array of shape (n_delta_t_values, n_atoms) results.delta_t_values : :class:`numpy.ndarray` - - Array of unique Δt (time differences) at which time-averaged MSD values are + Array of unique Δt (time differences) at which time-averaged MSD values are computed (for `non_linear=True`). - - For `non_linear=False` it is Null array. Time differences are same as the lag-times. - (To access: `lagtimes = np.arange(nframes)*timestep`) + For `non_linear=False` it is Null array. Time differences are same as the lag-times. + (To access: `lagtimes = np.arange(nframes)*timestep`). .. versionadded:: 2.10.0 From 1a24e36e87f2f57f08db7415c00cad1a554ecedb Mon Sep 17 00:00:00 2001 From: Oliver Beckstein Date: Fri, 1 Aug 2025 09:32:59 -0700 Subject: [PATCH 20/26] update warning in msd docs - point to nojump transformation (which has been available since 2.5.0) - add link to gmx trjconv --- package/MDAnalysis/analysis/msd.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 22377c2f33..a548cacb01 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -63,15 +63,23 @@ the normal MDAnalysis citations. .. warning:: - To correctly compute the MSD using this analysis module, you must supply - coordinates in the **unwrapped** convention. That is, when atoms pass - the periodic boundary, they must not be **wrapped** back into the primary - simulation cell. MDAnalysis does not currently offer this functionality in - the ``MDAnalysis.transformations`` API despite having functions with - similar names. We plan to implement the appropriate transformations in the - future. In the meantime, various simulation packages provide utilities to - convert coordinates to the unwrapped convention. In GROMACS for example, - this can be done using ``gmx trjconv`` with the ``-pbc nojump`` flag. + To correctly compute the MSD using this analysis module, you must supply + coordinates in the **unwrapped** convention, also known as **no-jump**. + That is, when atoms pass the periodic boundary, they must not be wrapped + back into the primary simulation cell. + + In MDAnalysis you can use the + :class:`~MDAnalysis.transformations.nojump.NoJump` + transformation. + + In GROMACS, for example, this can be done using `gmx trjconv`_ with the + ``-pbc nojump`` flag. + +.. _`gmx trjconv`: https://manual.gromacs.org/current/onlinehelp/gmx-trjconv.html + +.. SeeAlso:: + :mod:`MDAnalysis.transformations.nojump` + Computing an MSD ---------------- From daad5196ea774899c1862bc594e26b652c749891 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Thu, 14 Aug 2025 19:09:54 -0400 Subject: [PATCH 21/26] Testing doc formatting, WIP --- package/MDAnalysis/analysis/msd.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index a548cacb01..88263c3ed8 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -110,6 +110,7 @@ .. code-block:: python msd = MSD.results.timeseries + lagtimes = MSD.results.delta_t_values Visual inspection of the MSD is important, so let's take a look at it with a simple plot. @@ -117,8 +118,6 @@ import matplotlib.pyplot as plt nframes = MSD.n_frames - timestep = 1 # this needs to be the actual time between frames - lagtimes = np.arange(nframes)*timestep # make the lag-time axis fig = plt.figure() ax = plt.axes() # plot the actual MSD @@ -307,13 +306,11 @@ class EinsteinMSD(AnalysisBase): results.msds_by_particle : :class:`numpy.ndarray` The MSD of each individual particle with respect to constant lag-time or unique Δt intervals. - for `non_linear=False`: a 2D array of shape (n_lagtimes, n_atoms) - for `non_linear=True`: a 2D array of shape (n_delta_t_values, n_atoms) + - for `non_linear=False`: a 2D array of shape (n_lagtimes, n_atoms) + - for `non_linear=True`: a 2D array of shape (n_delta_t_values, n_atoms) results.delta_t_values : :class:`numpy.ndarray` Array of unique Δt (time differences) at which time-averaged MSD values are - computed (for `non_linear=True`). - For `non_linear=False` it is Null array. Time differences are same as the lag-times. - (To access: `lagtimes = np.arange(nframes)*timestep`). + computed. .. versionadded:: 2.10.0 @@ -419,12 +416,16 @@ def _conclude(self): def _conclude_simple(self): r"""Calculates the MSD via the simple "windowed" algorithm.""" lagtimes = np.arange(1, self.n_frames) + dump_times = self.times positions = self._position_array.astype(np.float64) for lag in tqdm(lagtimes): disp = positions[:-lag, :, :] - positions[lag:, :, :] sqdist = np.square(disp).sum(axis=-1) self.results.msds_by_particle[lag, :] = np.mean(sqdist, axis=0) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) + self.results.delta_t_values = np.arange(self.n_frames) * [ + dump_times[1] - dump_times[0] + ] def _conclude_fft(self): # with FFT, np.float64 bit prescision required. r"""Calculates the MSD via the FCA fast correlation algorithm.""" @@ -443,12 +444,16 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. or set fft=False""" ) + dump_times = self.times positions = self._position_array.astype(np.float64) for n in tqdm(range(self.n_particles)): self.results.msds_by_particle[:, n] = tidynamics.msd( positions[:, n, :] ) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) + self.results.delta_t_values = np.arange(self.n_frames) * [ + dump_times[1] - dump_times[0] + ] def _conclude_non_linear(self): From b578a670fe6f4d02ff858af49e63649c34a1856d Mon Sep 17 00:00:00 2001 From: gitsirsha Date: Sat, 16 Aug 2025 15:22:09 -0400 Subject: [PATCH 22/26] Update self.results.delta_t_values #1 Co-authored-by: Oliver Beckstein --- package/MDAnalysis/analysis/msd.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 88263c3ed8..7278205a71 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -423,9 +423,7 @@ def _conclude_simple(self): sqdist = np.square(disp).sum(axis=-1) self.results.msds_by_particle[lag, :] = np.mean(sqdist, axis=0) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) - self.results.delta_t_values = np.arange(self.n_frames) * [ - dump_times[1] - dump_times[0] - ] +self.results.delta_t_values = np.arange(self.n_frames) * (self.times[1] - self.times[0]) def _conclude_fft(self): # with FFT, np.float64 bit prescision required. r"""Calculates the MSD via the FCA fast correlation algorithm.""" From e26f53a7a6b50de01d35cd12c1b0dbdf4f61ca06 Mon Sep 17 00:00:00 2001 From: gitsirsha Date: Sat, 16 Aug 2025 15:22:39 -0400 Subject: [PATCH 23/26] Update self.results.delta_t_values #2 Co-authored-by: Oliver Beckstein --- package/MDAnalysis/analysis/msd.py | 1 - 1 file changed, 1 deletion(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 7278205a71..b9d4a43972 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -455,7 +455,6 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. def _conclude_non_linear(self): - dump_times = self.times n_frames = self.n_frames n_atoms = self.n_particles positions = self._position_array.astype(np.float64) From 125e710c966a7e1694f6979c324e871b9b1457d4 Mon Sep 17 00:00:00 2001 From: gitsirsha Date: Sat, 16 Aug 2025 15:23:14 -0400 Subject: [PATCH 24/26] Update self.results.delta_t_values #3 Co-authored-by: Oliver Beckstein --- package/MDAnalysis/analysis/msd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index b9d4a43972..488a16c570 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -468,7 +468,7 @@ def _conclude_non_linear(self): # Looping over all the frames as if the referenced gets shifted frame to frame for i in range(n_frames): for j in range(i + 1, n_frames): - delta_t = dump_times[j] - dump_times[i] + delta_t = self.times[j] - self.times[i] # Compute displacement and squared displacement disp = positions[j] - positions[i] squared_disp = np.sum(disp**2, axis=1) From 498a061a5fcbe6b1978da9f9e84f811aff1fd12b Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Sat, 16 Aug 2025 15:38:19 -0400 Subject: [PATCH 25/26] weird formatting edits --- package/MDAnalysis/analysis/msd.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index 488a16c570..c8c537fe30 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -178,8 +178,7 @@ start_time = 20 start_index = int(start_time/timestep) end_time = 60 - linear_model = linregress(lagtimes[start_index:end_index], - msd[start_index:end_index]) + linear_model = linregress(lagtimes[start_index:end_index], msd[start_index:end_index]) slope = linear_model.slope error = linear_model.stderr # dim_fac is 3 as we computed a 3D msd with 'xyz' @@ -423,7 +422,9 @@ def _conclude_simple(self): sqdist = np.square(disp).sum(axis=-1) self.results.msds_by_particle[lag, :] = np.mean(sqdist, axis=0) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) -self.results.delta_t_values = np.arange(self.n_frames) * (self.times[1] - self.times[0]) + self.results.delta_t_values = np.arange(self.n_frames) * ( + self.times[1] - self.times[0] + ) def _conclude_fft(self): # with FFT, np.float64 bit prescision required. r"""Calculates the MSD via the FCA fast correlation algorithm.""" @@ -449,19 +450,17 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. positions[:, n, :] ) self.results.timeseries = self.results.msds_by_particle.mean(axis=1) - self.results.delta_t_values = np.arange(self.n_frames) * [ - dump_times[1] - dump_times[0] - ] + self.results.delta_t_values = np.arange(self.n_frames) * ( + self.times[1] - self.times[0] + ) def _conclude_non_linear(self): n_frames = self.n_frames n_atoms = self.n_particles positions = self._position_array.astype(np.float64) - - msd_dict = collections.defaultdict( - list - ) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} + # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} + msd_dict = collections.defaultdict(list) msds_by_particle_dict = collections.defaultdict(list) # TODO: optimize the code From 788758dfa665f3ffd9b367c967a24deb13ae9456 Mon Sep 17 00:00:00 2001 From: Sirsha Ganguly Date: Sat, 16 Aug 2025 15:40:33 -0400 Subject: [PATCH 26/26] removed dump_times --- package/MDAnalysis/analysis/msd.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/package/MDAnalysis/analysis/msd.py b/package/MDAnalysis/analysis/msd.py index c8c537fe30..3348bf6bc4 100644 --- a/package/MDAnalysis/analysis/msd.py +++ b/package/MDAnalysis/analysis/msd.py @@ -415,7 +415,6 @@ def _conclude(self): def _conclude_simple(self): r"""Calculates the MSD via the simple "windowed" algorithm.""" lagtimes = np.arange(1, self.n_frames) - dump_times = self.times positions = self._position_array.astype(np.float64) for lag in tqdm(lagtimes): disp = positions[:-lag, :, :] - positions[lag:, :, :] @@ -443,7 +442,6 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. or set fft=False""" ) - dump_times = self.times positions = self._position_array.astype(np.float64) for n in tqdm(range(self.n_particles)): self.results.msds_by_particle[:, n] = tidynamics.msd(