diff --git a/package/CHANGELOG b/package/CHANGELOG index 032f13996ab..c8ecb17ead5 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -177,6 +177,11 @@ Enhancements checking if it can be used in parallel analysis. (Issue #2996, PR #2950) Changes + * `hydrogenbonds.WaterBridgeAnalysis.generate_table()` now returns the table; as previously, + it also generates the `table` attribute but the attribute will be removed in 3.0.0. + * `hydrogenbonds.WaterBridgeAnalysis` now stores data using the + `hydrogenbonds.WaterBridgeAnalysis.results` attribute + (Issue #3261, Issue #3270) * Introduces a new converter API with all converters in MDAnalysis.converters (Issue #2790, PR #2882) * The ParmEd classes were moved to the `converters` module (PR #2882) @@ -258,6 +263,14 @@ Changes * Added OpenMM coordinate and topology converters (Issue #2863, PR #2917) Deprecations + * The `hydrogenbonds.WaterBridgeAnalysis.table` attribute is now deprecated and will + be removed in 3.0.0. + * The `hydrogenbonds.WaterBridgeAnalysis.network` attribute is now deprecated + in favour of `hydrogenbonds.WaterBridgeAnalysis.results.network`. It will be + removed in 3.0.0 (Issue #3261, Issue #3270) + * The `analysis.Contacts.timeseries` attribute is now deprecated in favour of + `analysis.Contacts.results.timeseries`. It will be removed in 3.0.0 + (Issue #3261) * In 3.0.0 the ParmEd classes will only be accessible from the `MDAnalysis.converters` module. * The `analysis.polymer.PersistenceLength.lb`, diff --git a/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py b/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py index 7f39dd09586..b2973daefe5 100644 --- a/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py +++ b/package/MDAnalysis/analysis/hydrogenbonds/wbridge_analysis.py @@ -87,10 +87,10 @@ Since the waters connecting the two ends of the selections are by nature a network. We provide a network representation of the water network. Water bridge data are returned per frame, which is stored in -:attr:`WaterBridgeAnalysis.network`. Each frame is represented as a dictionary, -where the keys are the hydrogen bonds originating from selection 1 and the -values are new dictionaries representing the hydrogen bonds coming out of the -corresponding molecules making hydrogen bonds with selection 1. +:attr:`WaterBridgeAnalysis.results.network`. Each frame is represented as a +dictionary, where the keys are the hydrogen bonds originating from selection +1 and the values are new dictionaries representing the hydrogen bonds coming +out of the corresponding molecules making hydrogen bonds with selection 1. As for the hydrogen bonds which reach the selection 2, the values of the corresponding keys are None. One example where selection 1 and selection 2 are @@ -122,14 +122,14 @@ -------------------- For lower order water bridges, it might be desirable to represent the -connections as :attr:`WaterBridgeAnalysis.timeseries`. The results are returned -per frame and are a list of hydrogen bonds between the selection 1 or selection -2 and the bridging waters. Due to the complexity of the higher order water -bridge and the fact that one hydrogen bond between two waters can appear in -both third and fourth order water bridge, the hydrogen bonds in the -:attr:`WaterBridgeAnalysis.timeseries` attribute are generated in a depth-first -search manner to avoid duplication. Example code of how -:attr:`WaterBridgeAnalysis.timeseries` is generated:: +connections as :attr:`WaterBridgeAnalysis.results.timeseries`. The results +are returned per frame and are a list of hydrogen bonds between the selection +1 or selection 2 and the bridging waters. Due to the complexity of the higher +order water bridge and the fact that one hydrogen bond between two waters can +appear in both third and fourth order water bridge, the hydrogen bonds in the +:attr:`WaterBridgeAnalysis.results.timeseries` attribute are generated in a +depth-first search manner to avoid duplication. Example code of how +:attr:`WaterBridgeAnalysis.results.timeseries` is generated:: def network2timeseries(network, timeseries): '''Traverse the network in a depth-first fashion. @@ -307,7 +307,7 @@ class WaterBridgeAnalysis_OtherFF(WaterBridgeAnalysis): # 3 2 SOL HW2 # 4 3 ASP OD1 # 5 3 ASP OD2 - print(w.timeseries) + print(w.results.timeseries) prints out :: @@ -675,9 +675,43 @@ def analysis(current, output, u, **kwargs): .. attribute:: timesteps List of the times of each timestep. This can be used together with - :attr:`~WaterBridgeAnalysis.timeseries` to find the specific time point - of a water bridge existence. + :attr:`~WaterBridgeAnalysis.results.timeseries` to find the specific + time point of a water bridge existence. + .. attribute:: results.network + + Network representation of the water network. + + .. versionadded:: 2.0.0 + + .. attribute:: network + + Alias to the :attr:`results.network` attribute. + + .. deprecated:: 2.0.0 + Will be removed in MDAnalysis 3.0.0. Please use + :attr:`results.network` instead. + + .. attribute:: table + + .. deprecated:: 2.0.0 + Will be removed in MDAnalysis 3.0.0. Please generate + the table with :meth:`generate_table` instead. + + .. attribute:: results.timeseries + + List of hydrogen bonds between the selection 1 or selection 2 + and the bridging waters, for each frame. + + .. versionadded:: 2.0.0 + + .. attribute:: timeseries + + Alias to the :attr:`results.timeseries` attribute. + + .. deprecated:: 2.0.0 + Will be removed in MDAnalysis 3.0.0. Please use + :attr:`results.timeseries` instead. """ from collections import defaultdict import logging @@ -698,10 +732,9 @@ class WaterBridgeAnalysis(AnalysisBase): The analysis of the trajectory is performed with the :meth:`WaterBridgeAnalysis.run` method. The result is stored in - :attr:`WaterBridgeAnalysis.timeseries`. See + :attr:`WaterBridgeAnalysis.results.timeseries`. See :meth:`~WaterBridgeAnalysis.run` for the format. - .. versionadded:: 0.17.0 """ @@ -750,7 +783,7 @@ def __init__(self, universe, selection1='protein', universe. The timeseries is accessible as the attribute - :attr:`WaterBridgeAnalysis.timeseries`. + :attr:`WaterBridgeAnalysis.results.timeseries`. If no hydrogen bonds are detected or if the initial check fails, look at the log output (enable with :func:`MDAnalysis.start_logging` and set @@ -921,7 +954,9 @@ def __init__(self, universe, selection1='protein', 'Invalid selection type {0!s}'.format( self.selection1_type)) - self._network = [] # final result accessed as self.network + # final result accessed as self.results.network + self.results.network = [] + self.results.timeseries = None self.timesteps = None # time for each frame self._log_parameters() @@ -1216,7 +1251,7 @@ def _single_frame(self): if self.update_water_selection: self._update_water_selection() else: - self._network.append(defaultdict(dict)) + self.results.network.append(defaultdict(dict)) return selection_1 = [] @@ -1366,18 +1401,19 @@ def traverse_water_network(graph, node, end, route, maxdepth, result): traverse_water_network(water_pool, next_mol, selection_2, route[:], self.order, result) - self._network.append(result['start']) + self.results.network.append(result['start']) def _traverse_water_network(self, graph, current, analysis_func=None, output=None, link_func=None, **kwargs): ''' - This function recursively traverses the water network self._network and - finds the hydrogen bonds which connect the current atom to the next - atom. The newly found hydrogen bond will be appended to the hydrogen - bonds connecting the selection 1 to the current atom via link_func. - When selection 2 is reached, the full list of hydrogen bonds - connecting the selection 1 to selection 2 will be fed into - analysis_func, which will then modify the output in place. + This function recursively traverses the water network + self.results.network and finds the hydrogen bonds which connect the + current atom to the next atom. The newly found hydrogen bond will be + appended to the hydrogen bonds connecting the selection 1 to the + current atom via link_func. When selection 2 is reached, the full list + of hydrogen bonds connecting the selection 1 to selection 2 will be + fed into analysis_func, which will then modify the output in place. + :param graph: The connection network describes the connection between the atoms in the water network. :param current: The hydrogen bonds from selection 1 until now. @@ -1484,16 +1520,6 @@ def _generate_timeseries(self, output_format=None): To find an acceptor atom in :attr:`Universe.atoms` by *index* one would use ``u.atoms[acceptor_index]``. - The :attr:`timeseries` is a managed attribute and it is generated - from the underlying data in :attr:`_network` every time the - attribute is accessed. It is therefore costly to call and if - :attr:`timeseries` is needed repeatedly it is recommended that you - assign to a variable:: - - w = WaterBridgeAnalysis(u) - w.run() - timeseries = w.timeseries - .. versionchanged 0.20.0 The :attr:`WaterBridgeAnalysis.timeseries` has been updated where the donor and acceptor string has been changed to tuple @@ -1507,7 +1533,7 @@ def analysis(current, output, *args, **kwargs): output = current timeseries = [] - for frame in self._network: + for frame in self.results.network: new_frame = [] self._traverse_water_network(frame, new_frame, analysis_func=analysis, @@ -1518,37 +1544,13 @@ def analysis(current, output, *args, **kwargs): for entry in new_frame]) return timeseries - timeseries = property(_generate_timeseries) - - def _get_network(self): - r'''Network representation of the water network. - - The output is generated per frame as is explained in - :ref:`wb_Analysis_Network`. Each hydrogen bond has a compact - representation of :: - - [sele1_acceptor_idx, None, sele2_donor_idx, donor_heavy_idx, - distance, angle] - - or :: - - [sele1_donor_idx, donor_heavy_idx, sele1_acceptor_idx, None, - distance, angle] - - The donor_heavy_idx is the heavy atom bonding to the proton and atoms - can be retrived from the universe:: - - atom = u.atoms[idx] - - .. versionadded:: 0.20.0 - - ''' - return self._network def set_network(self, network): - self._network = network - - network = property(_get_network, set_network) + wmsg = ("The `set_network` method was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.network` instead") + warnings.warn(wmsg, DeprecationWarning) + self.results.network = network @classmethod def _full_link(self, output, node): @@ -1622,10 +1624,10 @@ def count_by_type(self, analysis_func=None, **kwargs): analysis_func = self._count_by_type_analysis output = 'combined' - if self._network: - length = len(self._network) + if self.results.network: + length = len(self.results.network) result_dict = defaultdict(int) - for frame in self._network: + for frame in self.results.network: frame_dict = defaultdict(int) self._traverse_water_network(frame, [], analysis_func=analysis_func, @@ -1672,9 +1674,9 @@ def count_by_time(self, analysis_func=None, **kwargs): """ if analysis_func is None: analysis_func = self._count_by_time_analysis - if self._network: + if self.results.network: result = [] - for time, frame in zip(self.timesteps, self._network): + for time, frame in zip(self.timesteps, self.results.network): result_dict = defaultdict(int) self._traverse_water_network(frame, [], analysis_func=analysis_func, @@ -1702,7 +1704,7 @@ def timesteps_by_type(self, analysis_func=None, **kwargs): """Frames during which each water bridges existed, sorted by each water bridges. - Processes :attr:`WaterBridgeAnalysis._network` and returns a + Processes :attr:`WaterBridgeAnalysis.results.network` and returns a :class:`list` containing atom indices, residue names, residue numbers (from selection 1 and selection 2) and each timestep at which the water bridge was detected. @@ -1721,13 +1723,13 @@ def timesteps_by_type(self, analysis_func=None, **kwargs): analysis_func = self._timesteps_by_type_analysis output = 'combined' - if self._network: + if self.results.network: result = defaultdict(list) if self.timesteps is None: - timesteps = range(len(self._network)) + timesteps = range(len(self.results.network)) else: timesteps = self.timesteps - for time, frame in zip(timesteps, self._network): + for time, frame in zip(timesteps, self.results.network): self._traverse_water_network(frame, [], analysis_func=analysis_func, output=result, @@ -1750,20 +1752,40 @@ def timesteps_by_type(self, analysis_func=None, **kwargs): def generate_table(self, output_format=None): """Generate a normalised table of the results. - The table is stored as a :class:`numpy.recarray` in the - attribute :attr:`~WaterBridgeAnalysis.table`. + Parameters + ---------- + output_format : {'sele1_sele2', 'donor_acceptor'} + The output format of the `table` can be changed a fashion similar + to :attr:`WaterBridgeAnalysis.results.timeseries` by changing the + labels of the columns of the participating atoms. + + Returns + ------- + table : numpy.recarray + A "tidy" table with one hydrogen bond per row, labeled according to + `output_format` and containing information of atom_1, atom_2, + distance, and angle. - The output format of :attr:`~WaterBridgeAnalysis.table` can also be - changed using output_format in a fashion similar to - :attr:`WaterBridgeAnalysis.timeseries` + .. versionchanged:: 2.0.0 + Return the generated table (as well as storing it as :attr:`table`). + + .. deprecated:: 2.0.0 + In release 3.0.0, :meth:`generate_table()` will _only_ return the + table and no longer store it in :attr:`table`. """ output_format = output_format or self.output_format - if self._network == []: + if self.results.network == []: msg = "No data computed, do run() first." warnings.warn(msg, category=MissingDataWarning) logger.warning(msg) return None - timeseries = self._generate_timeseries(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 + timeseries = self._generate_timeseries(output_format) num_records = np.sum([len(hframe) for hframe in timeseries]) # build empty output table @@ -1805,3 +1827,24 @@ def generate_table(self, output_format=None): "WBridge: Stored results as table with %(num_records)d entries.", vars()) self.table = table + + return table + + def _conclude(self): + self.results.timeseries = self._generate_timeseries() + + @property + def network(self): + wmsg = ("The `network` attribute was deprecated in MDAnalysis 2.0.0 " + "and will be removed in MDAnalysis 3.0.0. Please use " + "`results.network` instead") + warnings.warn(wmsg, DeprecationWarning) + return self.results.network + + @property + def timeseries(self): + wmsg = ("The `timeseries` attribute was deprecated in MDAnalysis " + "2.0.0 and will be removed in MDAnalysis 3.0.0. Please use " + "`results.timeseries` instead") + warnings.warn(wmsg, DeprecationWarning) + return self.results.timeseries diff --git a/testsuite/MDAnalysisTests/analysis/test_wbridge.py b/testsuite/MDAnalysisTests/analysis/test_wbridge.py index ef767740d34..913b11da776 100644 --- a/testsuite/MDAnalysisTests/analysis/test_wbridge.py +++ b/testsuite/MDAnalysisTests/analysis/test_wbridge.py @@ -274,15 +274,15 @@ def wb_multiframe(): wb = WaterBridgeAnalysis(u, 'protein and (resid 1)', 'protein and (resid 4)', order=4) # Build an dummy WaterBridgeAnalysis object for testing - wb._network = [] - wb._network.append({(1, 0, 12, None, 2.0, 180.0): None}) - wb._network.append({(0, None, 12, 13, 2.0, 180.0): None}) - wb._network.append({(1, 0, 3, None, 2.0, 180.0): + wb.results.network = [] + wb.results.network.append({(1, 0, 12, None, 2.0, 180.0): None}) + wb.results.network.append({(0, None, 12, 13, 2.0, 180.0): None}) + wb.results.network.append({(1, 0, 3, None, 2.0, 180.0): {(4, 2, 12, None, 2.0, 180.0): None}}) - wb._network.append({(0, None, 3, 2, 2.0, 180.0): + 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}}}) - wb.timesteps = range(len(wb._network)) + wb.timesteps = range(len(wb.results.network)) return wb def test_nodata(self, universe_DA): @@ -310,21 +310,21 @@ def test_empty_selection(self, universe_DA): wb = WaterBridgeAnalysis(universe_DA, 'protein and (resid 9)', 'protein and (resid 10)', order=0) wb.run() - assert wb._network == [{}] + assert wb.results.network == [{}] def test_loop(self, universe_loop): '''Test if loop can be handled correctly''' wb = WaterBridgeAnalysis(universe_loop, 'protein and (resid 1)', 'protein and (resid 1 or resid 4)') wb.run() - assert_equal(len(wb._network[0].keys()), 2) + assert_equal(len(wb.results.network[0].keys()), 2) def test_donor_accepter(self, universe_DA): '''Test zeroth order donor to acceptor hydrogen bonding''' wb = WaterBridgeAnalysis(universe_DA, 'protein and (resid 1)', 'protein and (resid 4)', order=0, update_selection=True, debug=True) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (1, 0, 2, None)) def test_donor_accepter_heavy(self, universe_DA): @@ -332,7 +332,7 @@ def test_donor_accepter_heavy(self, universe_DA): wb = WaterBridgeAnalysis(universe_DA, 'protein and (resid 1)', 'protein and (resid 4)', order=0, update_selection=True, debug=True, distance_type='heavy') wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (1, 0, 2, None)) def test_donor_accepter_pbc(self, universe_DA_PBC): @@ -340,7 +340,7 @@ def test_donor_accepter_pbc(self, universe_DA_PBC): wb = WaterBridgeAnalysis(universe_DA_PBC, 'protein and (resid 1)', 'protein and (resid 4)', order=0, pbc=True) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (1, 0, 2, None)) def test_accepter_donor(self, universe_AD): @@ -348,7 +348,7 @@ def test_accepter_donor(self, universe_AD): wb = WaterBridgeAnalysis(universe_AD, 'protein and (resid 1)', 'protein and (resid 4)', order=0) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 1, 2)) def test_acceptor_water_accepter(self, universe_AWA): @@ -357,7 +357,7 @@ def test_acceptor_water_accepter(self, universe_AWA): wb = WaterBridgeAnalysis(universe_AWA, 'protein and (resid 1)', 'protein and (resid 4)') wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -369,7 +369,7 @@ def test_donor_water_accepter(self, universe_DWA): wb = WaterBridgeAnalysis(universe_DWA, 'protein and (resid 1)', 'protein and (resid 4)') wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (1, 0, 2, None)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 2, 4, None)) @@ -381,7 +381,7 @@ def test_acceptor_water_donor(self, universe_AWD): wb = WaterBridgeAnalysis(universe_AWD, 'protein and (resid 1)', 'protein and (resid 4)') wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (1, None, 3, 4)) @@ -393,7 +393,7 @@ def test_donor_water_donor(self, universe_DWD): wb = WaterBridgeAnalysis(universe_DWD, 'protein and (resid 1)', 'protein and (resid 4)') wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (1, 0, 2, None)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (2, None, 3, 4)) @@ -403,7 +403,7 @@ def test_empty(self, universe_empty): '''Test case where no water bridge exists''' wb = WaterBridgeAnalysis(universe_empty, 'protein', 'protein') wb.run(verbose=False) - assert_equal(wb._network[0], defaultdict(dict)) + assert_equal(wb.results.network[0], defaultdict(dict)) def test_same_selection(self, universe_DWA): ''' @@ -414,7 +414,7 @@ def test_same_selection(self, universe_DWA): wb = WaterBridgeAnalysis(universe_DWA, 'protein and resid 1', 'protein and resid 1') wb.run(verbose=False) - assert_equal(wb._network[0], defaultdict(dict)) + assert_equal(wb.results.network[0], defaultdict(dict)) def test_acceptor_2water_accepter(self, universe_AWWA): '''Test case where the hydrogen bond acceptor from selection 1 form second order @@ -423,12 +423,12 @@ def test_acceptor_2water_accepter(self, universe_AWWA): wb = WaterBridgeAnalysis(universe_AWWA, 'protein and (resid 1)', 'protein and (resid 4)') wb.run(verbose=False) - assert_equal(wb._network[0], defaultdict(dict)) + assert_equal(wb.results.network[0], defaultdict(dict)) # test second order wb = WaterBridgeAnalysis(universe_AWWA, 'protein and (resid 1)', 'protein and (resid 4)', order=2) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -439,7 +439,7 @@ def test_acceptor_2water_accepter(self, universe_AWWA): wb = WaterBridgeAnalysis(universe_AWWA, 'protein and (resid 1)', 'protein and (resid 4)', order=3) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -453,12 +453,12 @@ def test_acceptor_3water_accepter(self, universe_AWWWA): wb = WaterBridgeAnalysis(universe_AWWWA, 'protein and (resid 1)', 'protein and (resid 5)', order=2) wb.run(verbose=False) - assert_equal(wb._network[0], defaultdict(dict)) + assert_equal(wb.results.network[0], defaultdict(dict)) wb = WaterBridgeAnalysis(universe_AWWWA, 'protein and (resid 1)', 'protein and (resid 5)', order=3) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -471,7 +471,7 @@ def test_acceptor_3water_accepter(self, universe_AWWWA): wb = WaterBridgeAnalysis(universe_AWWWA, 'protein and (resid 1)', 'protein and (resid 5)', order=4) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -487,12 +487,12 @@ def test_acceptor_4water_accepter(self, universe_AWWWWA): wb = WaterBridgeAnalysis(universe_AWWWWA, 'protein and (resid 1)', 'protein and (resid 6)', order=3) wb.run(verbose=False) - assert_equal(wb._network[0], defaultdict(dict)) + assert_equal(wb.results.network[0], defaultdict(dict)) wb = WaterBridgeAnalysis(universe_AWWWWA, 'protein and (resid 1)', 'protein and (resid 6)', order=4) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -507,7 +507,7 @@ def test_acceptor_4water_accepter(self, universe_AWWWWA): wb = WaterBridgeAnalysis(universe_AWWWWA, 'protein and (resid 1)', 'protein and (resid 6)', order=5) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -526,7 +526,7 @@ def test_acceptor_22water_accepter(self, universe_branch): wb = WaterBridgeAnalysis(universe_branch, 'protein and (resid 1)', 'protein and (resid 4 or resid 5)', order=2) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) @@ -540,7 +540,7 @@ def test_timeseries_wba(self, universe_branch): 'protein and (resid 4 or resid 5)', order=2) wb.output_format = 'sele1_sele2' wb.run(verbose=False) - timeseries = sorted(wb.timeseries[0]) + 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'))) @@ -553,7 +553,7 @@ def test_timeseries_hba(self, universe_branch): 'protein and (resid 4 or resid 5)', order=2) wb.output_format = 'donor_acceptor' wb.run(verbose=False) - timeseries = sorted(wb.timeseries[0]) + 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'))) @@ -565,16 +565,16 @@ def test_acceptor_12water_accepter(self, universe_AWA_AWWA): wb = WaterBridgeAnalysis(universe_AWA_AWWA, 'protein and (resid 1 or resid 5)', 'protein and (resid 4 or resid 8)', order=1) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal(list(network.keys())[0][:4], (0, None, 2, 1)) second = network[list(network.keys())[0]] assert_equal(list(second.keys())[0][:4], (3, 1, 4, None)) assert_equal(second[list(second.keys())[0]], None) - network = wb._network[0] + network = wb.results.network[0] wb = WaterBridgeAnalysis(universe_AWA_AWWA, 'protein and (resid 1 or resid 5)', 'protein and (resid 4 or resid 8)', order=2) wb.run(verbose=False) - network = wb._network[0] + network = wb.results.network[0] assert_equal([(0, None, 2, 1), (5, None, 7, 6)], sorted([key[:4] for key in list(network.keys())])) @@ -710,13 +710,19 @@ def analysis(current, output, u): def test_generate_table_hba(self, wb_multiframe): '''Test generate table using hydrogen bond analysis format''' - wb_multiframe.generate_table(output_format='donor_acceptor') - assert_array_equal(sorted(wb_multiframe.table.donor_resid), [1, 1, 2, 2, 2, 6, 6]) + table = wb_multiframe.generate_table(output_format='donor_acceptor') + assert_array_equal( + sorted(table.donor_resid), + [1, 1, 2, 2, 2, 6, 6], + ) def test_generate_table_s1s2(self, wb_multiframe): '''Test generate table using hydrogen bond analysis format''' - wb_multiframe.generate_table(output_format='sele1_sele2') - assert_array_equal(sorted(wb_multiframe.table.sele1_resid), [1, 1, 1, 1, 2, 2, 3]) + table = wb_multiframe.generate_table(output_format='sele1_sele2') + assert_array_equal( + sorted(table.sele1_resid), + [1, 1, 1, 1, 2, 2, 3], + ) def test_timesteps_by_type(self, wb_multiframe): '''Test the timesteps_by_type function''' @@ -745,4 +751,17 @@ def test_duplicate_water(self): wb = WaterBridgeAnalysis(u, 'resname LEU and name O', 'resname LEU and name N H', order=4) wb.run() - assert len(wb.timeseries[0]) == 2 + assert len(wb.results.timeseries[0]) == 2 + + def test_warn_results_deprecated(self, universe_DA): + wb = WaterBridgeAnalysis(universe_DA, 'protein and (resid 9)', + 'protein and (resid 10)', order=0) + wb.run() + + wmsg = "The `network` attribute was deprecated in MDAnalysis 2.0.0" + with pytest.warns(DeprecationWarning, match=wmsg): + assert_equal(wb.network, wb.results.network) + + wmsg = "The `timeseries` attribute was deprecated in MDAnalysis 2.0.0" + with pytest.warns(DeprecationWarning, match=wmsg): + assert_equal(wb.timeseries, wb.results.timeseries)