From 89fca38e0bf9e4efda0c22e29691d1d3a548ae58 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Sat, 10 Oct 2026 15:33:41 +0530 Subject: [PATCH 01/13] Expose computed density in InterRDF results (#5362) --- package/MDAnalysis/analysis/rdf.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index acb22179e1..915f76b61e 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -361,7 +361,7 @@ def _single_frame(self): count, _ = np.histogram(dist, **self.rdf_settings) self.results.count += count - if self.norm == "rdf": + if self.norm in ["rdf", "density"]: self.results.volume_cum += self._ts.volume def _get_aggregator(self): @@ -381,7 +381,7 @@ def _conclude(self): vols = np.power(self.results.edges, 3) norm *= 4 / 3 * np.pi * np.diff(vols) - if self.norm == "rdf": + if self.norm in ["rdf", "density"]: # Number of each selection nA = len(self.g1) nB = len(self.g2) @@ -396,7 +396,12 @@ def _conclude(self): # Average number density self.volume_cum = self.results.volume_cum box_vol = self.volume_cum / self.n_frames - norm *= N / box_vol + + # Save the average density so it can be accessed by the user + self.results.density = N / box_vol + + if self.norm == "rdf": + norm *= self.results.density self.results.rdf = self.results.count / norm @@ -742,7 +747,7 @@ def _single_frame(self): idx2s = pairs[:, 1] self.results.count[i][idx1s, idx2s, bin_indices] += counts - if self.norm == "rdf": + if self.norm in ["rdf", "density"]: self.results.volume_cum += self._ts.volume def _conclude(self): From 4d8834b82f5475c1455bbeca5efd59a5bb6ba6f0 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Sat, 10 Oct 2026 15:42:29 +0530 Subject: [PATCH 02/13] Fix black formatting --- package/MDAnalysis/analysis/rdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index 915f76b61e..8f52ba2cf2 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -396,7 +396,7 @@ def _conclude(self): # Average number density self.volume_cum = self.results.volume_cum box_vol = self.volume_cum / self.n_frames - + # Save the average density so it can be accessed by the user self.results.density = N / box_vol From 6eb8e76d389b6c3aef284082133832ab5e8a2b67 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Sat, 10 Oct 2026 15:44:53 +0530 Subject: [PATCH 03/13] Fix volume_cum initialization in _prepare for norm=density --- package/MDAnalysis/analysis/rdf.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index 8f52ba2cf2..b4bd1ed698 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -330,7 +330,7 @@ def _prepare(self): self.results.edges = edges self.results.bins = 0.5 * (edges[:-1] + edges[1:]) - if self.norm == "rdf": + if self.norm in ["rdf", "density"]: # Cumulative volume for rdf normalization self.results.volume_cum = 0 # Set the max range to filter the search radius @@ -721,7 +721,7 @@ def _prepare(self): self.results.edges = edges self.results.bins = 0.5 * (edges[:-1] + edges[1:]) - if self.norm == "rdf": + if self.norm in ["rdf", "density"]: # Cumulative volume for rdf normalization self.results.volume_cum = 0 self._maxrange = self.rdf_settings["range"][1] @@ -757,10 +757,12 @@ def _conclude(self): vols = np.power(self.results.edges, 3) norm *= 4 / 3 * np.pi * np.diff(vols) - if self.norm == "rdf": + if self.norm in ["rdf", "density"]: # Average number density self.volume_cum = self.results.volume_cum - norm *= 1 / (self.volume_cum / self.n_frames) + self.results.density = self.n_frames / self.volume_cum + if self.norm == "rdf": + norm *= self.results.density # Empty lists to restore indices, RDF self.results.indices = [] From d6cd1fd47e623ce649356a0d645a6ed24188b590 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Mon, 12 Oct 2026 10:11:35 +0530 Subject: [PATCH 04/13] Guard against ZeroDivisionError when box_vol is zero in norm='density' - Only compute results.density/results.rho when box_vol > 0, otherwise set to None - Expose results.rho alias alongside results.density as suggested in #5362 --- package/MDAnalysis/analysis/rdf.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index b4bd1ed698..9d7287fe19 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -397,8 +397,13 @@ def _conclude(self): self.volume_cum = self.results.volume_cum box_vol = self.volume_cum / self.n_frames - # Save the average density so it can be accessed by the user - self.results.density = N / box_vol + # Save the average density if a non-zero box volume is available + if box_vol > 0: + self.results.density = N / box_vol + self.results.rho = self.results.density + else: + self.results.density = None + self.results.rho = None if self.norm == "rdf": norm *= self.results.density @@ -760,7 +765,13 @@ def _conclude(self): if self.norm in ["rdf", "density"]: # Average number density self.volume_cum = self.results.volume_cum - self.results.density = self.n_frames / self.volume_cum + if self.volume_cum > 0: + self.results.density = self.n_frames / self.volume_cum + self.results.rho = self.results.density + else: + self.results.density = None + self.results.rho = None + if self.norm == "rdf": norm *= self.results.density From 7b16b8ecc21800c67e90123731c82b14af5d5447 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Wed, 14 Oct 2026 08:28:22 +0530 Subject: [PATCH 05/13] Add tests, update CHANGELOG and AUTHORS for exposed density in InterRDF (#5362) --- package/AUTHORS | 1 + package/CHANGELOG | 4 +++- .../MDAnalysisTests/analysis/test_rdf.py | 21 +++++++++++++++++++ .../MDAnalysisTests/analysis/test_rdf_s.py | 4 ++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/package/AUTHORS b/package/AUTHORS index c8ba87c062..eae5eb09ea 100644 --- a/package/AUTHORS +++ b/package/AUTHORS @@ -285,6 +285,7 @@ Chronological list of authors - Apoorva Verma - Aryaman Chaudhri - Francesco Siciliani + - Sumit Saraswat External code ------------- diff --git a/package/CHANGELOG b/package/CHANGELOG index 426918e0e1..57eb2f5d53 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -18,7 +18,7 @@ The rules for this file: spyke7, talagayev, tanii1125, BradyAJohnston, hejamu, jeremyleung521, harshitgajjela-droid, kunjsinha, aygarwal, jauy123, Dreamstick9, ollyfutur, Amarendra22, charity-g, ParthUppal523, apoorva-01, RMeli, - raulloiscuns, Aryaman-Chaudhri, sici17 + raulloiscuns, Aryaman-Chaudhri, sici17, sumitsaraswat362 * 2.11.0 @@ -82,6 +82,8 @@ Fixes DSSP by porting upstream PyDSSP 0.9.1 fix (Issue #4913) Enhancements + * InterRDF and InterRDF_s now expose computed density as results.density + (and results.rho) when norm is "rdf" or "density" (Issue #5362, PR #5482) * Add reading single-frame files from mmCIF, also known as PDBx format, using crystallographic library `gemmi` as a backend (Issue #2367 and extension of #4303, also solves #5089, PR #4712). diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index 36da9be327..13e3d90c06 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -171,3 +171,24 @@ def test_backend(sels, backend): s1, s2 = sels rdf = InterRDF(s1, s2, norm="none", backend=backend).run() assert_allclose(max(rdf.results.rdf), 4) + + +def test_exposed_density(sels, client_InterRDF): + s1, s2 = sels + # When norm is "rdf" + rdf = InterRDF(s1, s2, norm="rdf").run(**client_InterRDF) + assert hasattr(rdf.results, "density") + assert rdf.results.density is not None + assert rdf.results.density > 0 + assert rdf.results.rho == rdf.results.density + + # When norm is "density" + rdf_dense = InterRDF(s1, s2, norm="density").run(**client_InterRDF) + assert hasattr(rdf_dense.results, "density") + assert rdf_dense.results.density is not None + assert rdf_dense.results.density > 0 + assert rdf_dense.results.rho == rdf_dense.results.density + + # When norm is "none" + rdf_none = InterRDF(s1, s2, norm="none").run(**client_InterRDF) + assert not hasattr(rdf_none.results, "density") diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index 5095c4d432..03a822b22f 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -120,6 +120,10 @@ def test_density(u, sels, density, value, client_InterRDF_s): kwargs = {"density": density} if density is not None else {} rdf = InterRDF_s(u, sels, **kwargs).run(**client_InterRDF_s) assert_almost_equal(max(rdf.results.rdf[0][0][0]), value) + assert hasattr(rdf.results, "density") + assert rdf.results.density is not None + assert rdf.results.density > 0 + assert rdf.results.rho == rdf.results.density if not density: s1 = u.select_atoms("name ZND and resid 289") s2 = u.select_atoms( From 9e8f74a5ccce54c367bfb8159e0e0cc75fb6b287 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Wed, 14 Oct 2026 08:46:43 +0530 Subject: [PATCH 06/13] Add tests for zero box volume density fallback in InterRDF and InterRDF_s --- testsuite/MDAnalysisTests/analysis/test_rdf.py | 12 ++++++++++++ testsuite/MDAnalysisTests/analysis/test_rdf_s.py | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index 13e3d90c06..aab50fe37e 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -192,3 +192,15 @@ def test_exposed_density(sels, client_InterRDF): # When norm is "none" rdf_none = InterRDF(s1, s2, norm="none").run(**client_InterRDF) assert not hasattr(rdf_none.results, "density") + + +def test_density_zero_box(u, client_InterRDF): + trajectory_data = np.tile(u.atoms.positions, (NFRAMES, 1, 1)) + dimensions_data = np.zeros((NFRAMES, 6)) + u.load_new(trajectory_data, format="MEMORY", dimensions=dimensions_data) + s1 = u.select_atoms("name OW") + s2 = u.select_atoms("name HW1 HW2") + rdf = InterRDF(s1, s2, norm="density").run(**client_InterRDF) + assert hasattr(rdf.results, "density") + assert rdf.results.density is None + assert rdf.results.rho is None diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index 03a822b22f..3a41e58e16 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -202,3 +202,17 @@ def test_nested_array_sum(): assert np.array_equal(result[0], arr_1 + arr_3) assert np.array_equal(result[1], arr_2 + arr_4) + + +def test_density_zero_box(client_InterRDF_s): + u = mda.Universe(GRO_MEMPROT, in_memory=True) + trajectory_data = np.tile(u.atoms.positions, (2, 1, 1)) + dimensions_data = np.zeros((2, 6)) + u.load_new(trajectory_data, format="MEMORY", dimensions=dimensions_data) + s1 = u.select_atoms("name ZND and resid 289") + s2 = u.select_atoms("name OD1 and resid 51") + ags = [[s1, s2]] + rdf = InterRDF_s(u, ags, norm="density").run(**client_InterRDF_s) + assert hasattr(rdf.results, "density") + assert rdf.results.density is None + assert rdf.results.rho is None From deb1c8a5fd4a0a71500bec56dbf3edb67716b112 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Fri, 16 Oct 2026 14:53:34 +0530 Subject: [PATCH 07/13] DOC, ENH: document results.density and drop results.rho --- package/MDAnalysis/analysis/rdf.py | 18 ++++++++++++++---- testsuite/MDAnalysisTests/analysis/test_rdf.py | 4 +--- .../MDAnalysisTests/analysis/test_rdf_s.py | 2 -- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index 9d7287fe19..560bcdd97e 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -229,6 +229,13 @@ class InterRDF(AnalysisBase): This attribute will be removed in 3.0.0. Use :attr:`results.count` instead. + results.density : float + The average number density :math:`\rho` used for normalizing the RDF + (or ``None`` if box volume is not available). This attribute only + exists if `norm` is ``"rdf"`` or ``"density"``. + + .. versionadded:: 2.11.0 + Example ------- First create the :class:`InterRDF` object, by supplying two @@ -400,10 +407,8 @@ def _conclude(self): # Save the average density if a non-zero box volume is available if box_vol > 0: self.results.density = N / box_vol - self.results.rho = self.results.density else: self.results.density = None - self.results.rho = None if self.norm == "rdf": norm *= self.results.density @@ -591,6 +596,13 @@ class InterRDF_s(AnalysisBase): This attribute will be removed in 3.0.0. Use :attr:`results.cdf` instead. + results.density : float + The average number density :math:`\rho` used for normalizing the RDF + (or ``None`` if box volume is not available). This attribute only + exists if `norm` is ``"rdf"`` or ``"density"``. + + .. versionadded:: 2.11.0 + Example ------- First create the :class:`InterRDF_s` object, by supplying one Universe and @@ -767,10 +779,8 @@ def _conclude(self): self.volume_cum = self.results.volume_cum if self.volume_cum > 0: self.results.density = self.n_frames / self.volume_cum - self.results.rho = self.results.density else: self.results.density = None - self.results.rho = None if self.norm == "rdf": norm *= self.results.density diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index aab50fe37e..c42d385240 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -180,14 +180,12 @@ def test_exposed_density(sels, client_InterRDF): assert hasattr(rdf.results, "density") assert rdf.results.density is not None assert rdf.results.density > 0 - assert rdf.results.rho == rdf.results.density # When norm is "density" rdf_dense = InterRDF(s1, s2, norm="density").run(**client_InterRDF) assert hasattr(rdf_dense.results, "density") assert rdf_dense.results.density is not None assert rdf_dense.results.density > 0 - assert rdf_dense.results.rho == rdf_dense.results.density # When norm is "none" rdf_none = InterRDF(s1, s2, norm="none").run(**client_InterRDF) @@ -203,4 +201,4 @@ def test_density_zero_box(u, client_InterRDF): rdf = InterRDF(s1, s2, norm="density").run(**client_InterRDF) assert hasattr(rdf.results, "density") assert rdf.results.density is None - assert rdf.results.rho is None + diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index 3a41e58e16..1ac13b068e 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -123,7 +123,6 @@ def test_density(u, sels, density, value, client_InterRDF_s): assert hasattr(rdf.results, "density") assert rdf.results.density is not None assert rdf.results.density > 0 - assert rdf.results.rho == rdf.results.density if not density: s1 = u.select_atoms("name ZND and resid 289") s2 = u.select_atoms( @@ -215,4 +214,3 @@ def test_density_zero_box(client_InterRDF_s): rdf = InterRDF_s(u, ags, norm="density").run(**client_InterRDF_s) assert hasattr(rdf.results, "density") assert rdf.results.density is None - assert rdf.results.rho is None From 359495fc3988c160b4d76f5aafc258e86fcd1a15 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Fri, 16 Oct 2026 15:00:20 +0530 Subject: [PATCH 08/13] MAINT: fix trailing newline in test_rdf.py for black --- testsuite/MDAnalysisTests/analysis/test_rdf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index c42d385240..e5a9d62498 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -201,4 +201,3 @@ def test_density_zero_box(u, client_InterRDF): rdf = InterRDF(s1, s2, norm="density").run(**client_InterRDF) assert hasattr(rdf.results, "density") assert rdf.results.density is None - From 8e84db04ccdf2ef8cd0f2e332d6fa3c3c668441e Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Sun, 18 Oct 2026 00:20:29 +0530 Subject: [PATCH 09/13] DOC, ENH: store normalization_density, box_volume and selection densities (#5362) --- package/CHANGELOG | 6 +- package/MDAnalysis/analysis/rdf.py | 76 ++++++++++++++----- .../MDAnalysisTests/analysis/test_rdf.py | 45 +++++++++-- .../MDAnalysisTests/analysis/test_rdf_s.py | 15 ++-- 4 files changed, 110 insertions(+), 32 deletions(-) diff --git a/package/CHANGELOG b/package/CHANGELOG index d254c2d2d4..b0c1576531 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -83,8 +83,10 @@ Fixes DSSP by porting upstream PyDSSP 0.9.1 fix (Issue #4913) Enhancements - * InterRDF and InterRDF_s now expose computed density as results.density - when norm is "rdf" or "density" (Issue #5362, PR #5482) + * InterRDF and InterRDF_s now expose computed average box volume and densities + as results.box_volume, results.normalization_density, and (for InterRDF) + results.density_a and results.density_b when norm is "rdf" or "density" + (Issue #5362, PR #5482) * Add reading single-frame files from mmCIF, also known as PDBx format, using crystallographic library `gemmi` as a backend (Issue #2367 and extension of #4303, also solves #5089, PR #4712). diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index 560bcdd97e..2ed27d810f 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -229,10 +229,36 @@ class InterRDF(AnalysisBase): This attribute will be removed in 3.0.0. Use :attr:`results.count` instead. - results.density : float - The average number density :math:`\rho` used for normalizing the RDF - (or ``None`` if box volume is not available). This attribute only - exists if `norm` is ``"rdf"`` or ``"density"``. + results.normalization_density : float + The pair normalization density :math:`N_{\text{pairs}} / \langle V \rangle` + used to normalize the RDF (or ``None`` if box volume is not available), + where :math:`\langle V \rangle` is the average box volume and + :math:`N_{\text{pairs}} = N_a N_b - N_{\text{excl}}`. + This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. + + .. versionadded:: 2.11.0 + + results.box_volume : float + The average box volume :math:`\langle V \rangle` across analyzed frames + (or ``None`` if box volume is not available). + This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. + + .. versionadded:: 2.11.0 + + results.density_a : float + The bulk number density :math:`\rho_a = N_a / \langle V \rangle` of the + first selection `g1` (or ``None`` if box volume is not available). + This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. + + .. versionadded:: 2.11.0 + + results.density_b : float + The bulk number density :math:`\rho_b = N_b / \langle V \rangle` of the + second selection `g2` (or ``None`` if box volume is not available). + This corresponds to the bulk density :math:`\rho` appearing in the + equations for :ref:`cumulative coordination counts` + and :ref:`radial densities`. + This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. .. versionadded:: 2.11.0 @@ -400,18 +426,23 @@ def _conclude(self): nblocks = nA / xA N -= xA * xB * nblocks - # Average number density + # Average box volume and densities self.volume_cum = self.results.volume_cum box_vol = self.volume_cum / self.n_frames - # Save the average density if a non-zero box volume is available if box_vol > 0: - self.results.density = N / box_vol + self.results.box_volume = box_vol + self.results.normalization_density = N / box_vol + self.results.density_a = nA / box_vol + self.results.density_b = nB / box_vol else: - self.results.density = None + self.results.box_volume = None + self.results.normalization_density = None + self.results.density_a = None + self.results.density_b = None if self.norm == "rdf": - norm *= self.results.density + norm *= self.results.normalization_density self.results.rdf = self.results.count / norm @@ -596,10 +627,18 @@ class InterRDF_s(AnalysisBase): This attribute will be removed in 3.0.0. Use :attr:`results.cdf` instead. - results.density : float - The average number density :math:`\rho` used for normalizing the RDF - (or ``None`` if box volume is not available). This attribute only - exists if `norm` is ``"rdf"`` or ``"density"``. + results.normalization_density : float + The normalization density :math:`1 / \langle V \rangle` used for + normalizing site-specific pair RDFs (or ``None`` if box volume is not + available), where :math:`\langle V \rangle` is the average box volume. + This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. + + .. versionadded:: 2.11.0 + + results.box_volume : float + The average box volume :math:`\langle V \rangle` across analyzed frames + (or ``None`` if box volume is not available). + This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. .. versionadded:: 2.11.0 @@ -775,15 +814,18 @@ def _conclude(self): norm *= 4 / 3 * np.pi * np.diff(vols) if self.norm in ["rdf", "density"]: - # Average number density + # Average box volume and normalization density self.volume_cum = self.results.volume_cum if self.volume_cum > 0: - self.results.density = self.n_frames / self.volume_cum + box_vol = self.volume_cum / self.n_frames + self.results.box_volume = box_vol + self.results.normalization_density = 1.0 / box_vol else: - self.results.density = None + self.results.box_volume = None + self.results.normalization_density = None if self.norm == "rdf": - norm *= self.results.density + norm *= self.results.normalization_density # Empty lists to restore indices, RDF self.results.indices = [] diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index e5a9d62498..2e817b0acc 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -177,19 +177,41 @@ def test_exposed_density(sels, client_InterRDF): s1, s2 = sels # When norm is "rdf" rdf = InterRDF(s1, s2, norm="rdf").run(**client_InterRDF) - assert hasattr(rdf.results, "density") - assert rdf.results.density is not None - assert rdf.results.density > 0 + assert not hasattr(rdf.results, "density") + assert hasattr(rdf.results, "box_volume") + assert hasattr(rdf.results, "normalization_density") + assert hasattr(rdf.results, "density_a") + assert hasattr(rdf.results, "density_b") + assert rdf.results.box_volume > 0 + assert_allclose(rdf.results.density_a, len(s1) / rdf.results.box_volume) + assert_allclose(rdf.results.density_b, len(s2) / rdf.results.box_volume) + assert_allclose( + rdf.results.normalization_density, + (len(s1) * len(s2)) / rdf.results.box_volume, + ) # When norm is "density" rdf_dense = InterRDF(s1, s2, norm="density").run(**client_InterRDF) - assert hasattr(rdf_dense.results, "density") - assert rdf_dense.results.density is not None - assert rdf_dense.results.density > 0 + assert not hasattr(rdf_dense.results, "density") + assert hasattr(rdf_dense.results, "box_volume") + assert hasattr(rdf_dense.results, "normalization_density") + assert hasattr(rdf_dense.results, "density_a") + assert hasattr(rdf_dense.results, "density_b") + assert rdf_dense.results.box_volume > 0 + assert_allclose(rdf_dense.results.density_a, len(s1) / rdf_dense.results.box_volume) + assert_allclose(rdf_dense.results.density_b, len(s2) / rdf_dense.results.box_volume) + assert_allclose( + rdf_dense.results.normalization_density, + (len(s1) * len(s2)) / rdf_dense.results.box_volume, + ) # When norm is "none" rdf_none = InterRDF(s1, s2, norm="none").run(**client_InterRDF) assert not hasattr(rdf_none.results, "density") + assert not hasattr(rdf_none.results, "box_volume") + assert not hasattr(rdf_none.results, "normalization_density") + assert not hasattr(rdf_none.results, "density_a") + assert not hasattr(rdf_none.results, "density_b") def test_density_zero_box(u, client_InterRDF): @@ -199,5 +221,12 @@ def test_density_zero_box(u, client_InterRDF): s1 = u.select_atoms("name OW") s2 = u.select_atoms("name HW1 HW2") rdf = InterRDF(s1, s2, norm="density").run(**client_InterRDF) - assert hasattr(rdf.results, "density") - assert rdf.results.density is None + assert not hasattr(rdf.results, "density") + assert hasattr(rdf.results, "box_volume") + assert hasattr(rdf.results, "normalization_density") + assert hasattr(rdf.results, "density_a") + assert hasattr(rdf.results, "density_b") + assert rdf.results.box_volume is None + assert rdf.results.normalization_density is None + assert rdf.results.density_a is None + assert rdf.results.density_b is None diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index 1ac13b068e..9f86a8be73 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -120,9 +120,11 @@ def test_density(u, sels, density, value, client_InterRDF_s): kwargs = {"density": density} if density is not None else {} rdf = InterRDF_s(u, sels, **kwargs).run(**client_InterRDF_s) assert_almost_equal(max(rdf.results.rdf[0][0][0]), value) - assert hasattr(rdf.results, "density") - assert rdf.results.density is not None - assert rdf.results.density > 0 + assert not hasattr(rdf.results, "density") + assert hasattr(rdf.results, "box_volume") + assert hasattr(rdf.results, "normalization_density") + assert rdf.results.box_volume > 0 + assert_allclose(rdf.results.normalization_density, 1.0 / rdf.results.box_volume) if not density: s1 = u.select_atoms("name ZND and resid 289") s2 = u.select_atoms( @@ -212,5 +214,8 @@ def test_density_zero_box(client_InterRDF_s): s2 = u.select_atoms("name OD1 and resid 51") ags = [[s1, s2]] rdf = InterRDF_s(u, ags, norm="density").run(**client_InterRDF_s) - assert hasattr(rdf.results, "density") - assert rdf.results.density is None + assert not hasattr(rdf.results, "density") + assert hasattr(rdf.results, "box_volume") + assert hasattr(rdf.results, "normalization_density") + assert rdf.results.box_volume is None + assert rdf.results.normalization_density is None From 47aac895dafef4c3ed5a009556e34d9da81afc2a Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Sun, 18 Oct 2026 00:24:23 +0530 Subject: [PATCH 10/13] MAINT: format test files with black --- testsuite/MDAnalysisTests/analysis/test_rdf.py | 8 ++++++-- testsuite/MDAnalysisTests/analysis/test_rdf_s.py | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index 2e817b0acc..6d23b1c074 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -198,8 +198,12 @@ def test_exposed_density(sels, client_InterRDF): assert hasattr(rdf_dense.results, "density_a") assert hasattr(rdf_dense.results, "density_b") assert rdf_dense.results.box_volume > 0 - assert_allclose(rdf_dense.results.density_a, len(s1) / rdf_dense.results.box_volume) - assert_allclose(rdf_dense.results.density_b, len(s2) / rdf_dense.results.box_volume) + assert_allclose( + rdf_dense.results.density_a, len(s1) / rdf_dense.results.box_volume + ) + assert_allclose( + rdf_dense.results.density_b, len(s2) / rdf_dense.results.box_volume + ) assert_allclose( rdf_dense.results.normalization_density, (len(s1) * len(s2)) / rdf_dense.results.box_volume, diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index 9f86a8be73..b2c8051449 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -124,7 +124,9 @@ def test_density(u, sels, density, value, client_InterRDF_s): assert hasattr(rdf.results, "box_volume") assert hasattr(rdf.results, "normalization_density") assert rdf.results.box_volume > 0 - assert_allclose(rdf.results.normalization_density, 1.0 / rdf.results.box_volume) + assert_allclose( + rdf.results.normalization_density, 1.0 / rdf.results.box_volume + ) if not density: s1 = u.select_atoms("name ZND and resid 289") s2 = u.select_atoms( From a3c97e0cdc9d279301f7d4a59eadf872dcf5ba54 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Tue, 20 Oct 2026 09:32:51 +0530 Subject: [PATCH 11/13] DOC, TEST, MAINT: rename to density_1/density_2 and parametrize tests (#5362) --- package/CHANGELOG | 2 +- package/MDAnalysis/analysis/rdf.py | 28 ++++---- .../MDAnalysisTests/analysis/test_rdf.py | 67 +++++++------------ .../MDAnalysisTests/analysis/test_rdf_s.py | 17 ++--- 4 files changed, 42 insertions(+), 72 deletions(-) diff --git a/package/CHANGELOG b/package/CHANGELOG index b934794f2f..e70fe474f9 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -112,7 +112,7 @@ Fixes Enhancements * InterRDF and InterRDF_s now expose computed average box volume and densities as results.box_volume, results.normalization_density, and (for InterRDF) - results.density_a and results.density_b when norm is "rdf" or "density" + results.density_1 and results.density_2 when norm is "rdf" or "density" (Issue #5362, PR #5482) * Add reading single-frame files from mmCIF, also known as PDBx format, using crystallographic library `gemmi` as a backend (Issue #2367 and extension of diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index bb2e5cfa0c..4b7e0a8446 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -221,7 +221,7 @@ class InterRDF(AnalysisBase): The pair normalization density :math:`N_{\text{pairs}} / \langle V \rangle` used to normalize the RDF (or ``None`` if box volume is not available), where :math:`\langle V \rangle` is the average box volume and - :math:`N_{\text{pairs}} = N_a N_b - N_{\text{excl}}`. + :math:`N_{\text{pairs}} = N_1 N_2 - N_{\text{excl}}`. This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. .. versionadded:: 2.11.0 @@ -233,15 +233,15 @@ class InterRDF(AnalysisBase): .. versionadded:: 2.11.0 - results.density_a : float - The bulk number density :math:`\rho_a = N_a / \langle V \rangle` of the + results.density_1 : float + The bulk number density :math:`\rho_1 = N_1 / \langle V \rangle` of the first selection `g1` (or ``None`` if box volume is not available). This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. .. versionadded:: 2.11.0 - results.density_b : float - The bulk number density :math:`\rho_b = N_b / \langle V \rangle` of the + results.density_2 : float + The bulk number density :math:`\rho_2 = N_2 / \langle V \rangle` of the second selection `g2` (or ``None`` if box volume is not available). This corresponds to the bulk density :math:`\rho` appearing in the equations for :ref:`cumulative coordination counts` @@ -336,8 +336,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 @@ -421,13 +420,13 @@ def _conclude(self): if box_vol > 0: self.results.box_volume = box_vol self.results.normalization_density = N / box_vol - self.results.density_a = nA / box_vol - self.results.density_b = nB / box_vol + self.results.density_1 = nA / box_vol + self.results.density_2 = nB / box_vol else: self.results.box_volume = None self.results.normalization_density = None - self.results.density_a = None - self.results.density_b = None + self.results.density_1 = None + self.results.density_2 = None if self.norm == "rdf": norm *= self.results.normalization_density @@ -724,9 +723,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 " @@ -740,8 +737,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/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index 6d23b1c074..01a9dda25b 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -106,9 +106,7 @@ def test_exclusion(sels, client_InterRDF): assert rdf.results.count.sum() == 4 * NFRAMES -@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, client_InterRDF): # should see two distances with 4 counts each s1, s2 = sels @@ -173,49 +171,33 @@ def test_backend(sels, backend): assert_allclose(max(rdf.results.rdf), 4) -def test_exposed_density(sels, client_InterRDF): +@pytest.mark.parametrize("norm", ("rdf", "density")) +def test_exposed_density(sels, norm, client_InterRDF): s1, s2 = sels - # When norm is "rdf" - rdf = InterRDF(s1, s2, norm="rdf").run(**client_InterRDF) - assert not hasattr(rdf.results, "density") + expected_volume = 1_000_000.0 + rdf = InterRDF(s1, s2, norm=norm).run(**client_InterRDF) + assert hasattr(rdf.results, "box_volume") assert hasattr(rdf.results, "normalization_density") - assert hasattr(rdf.results, "density_a") - assert hasattr(rdf.results, "density_b") - assert rdf.results.box_volume > 0 - assert_allclose(rdf.results.density_a, len(s1) / rdf.results.box_volume) - assert_allclose(rdf.results.density_b, len(s2) / rdf.results.box_volume) + assert hasattr(rdf.results, "density_1") + assert hasattr(rdf.results, "density_2") + + assert_allclose(rdf.results.box_volume, expected_volume) + assert_allclose(rdf.results.density_1, len(s1) / expected_volume) + assert_allclose(rdf.results.density_2, len(s2) / expected_volume) assert_allclose( rdf.results.normalization_density, - (len(s1) * len(s2)) / rdf.results.box_volume, + (len(s1) * len(s2)) / expected_volume, ) - # When norm is "density" - rdf_dense = InterRDF(s1, s2, norm="density").run(**client_InterRDF) - assert not hasattr(rdf_dense.results, "density") - assert hasattr(rdf_dense.results, "box_volume") - assert hasattr(rdf_dense.results, "normalization_density") - assert hasattr(rdf_dense.results, "density_a") - assert hasattr(rdf_dense.results, "density_b") - assert rdf_dense.results.box_volume > 0 - assert_allclose( - rdf_dense.results.density_a, len(s1) / rdf_dense.results.box_volume - ) - assert_allclose( - rdf_dense.results.density_b, len(s2) / rdf_dense.results.box_volume - ) - assert_allclose( - rdf_dense.results.normalization_density, - (len(s1) * len(s2)) / rdf_dense.results.box_volume, - ) - # When norm is "none" - rdf_none = InterRDF(s1, s2, norm="none").run(**client_InterRDF) - assert not hasattr(rdf_none.results, "density") - assert not hasattr(rdf_none.results, "box_volume") - assert not hasattr(rdf_none.results, "normalization_density") - assert not hasattr(rdf_none.results, "density_a") - assert not hasattr(rdf_none.results, "density_b") +def test_exposed_density_norm_none(sels, client_InterRDF): + s1, s2 = sels + rdf = InterRDF(s1, s2, norm="none").run(**client_InterRDF) + assert not hasattr(rdf.results, "box_volume") + assert not hasattr(rdf.results, "normalization_density") + assert not hasattr(rdf.results, "density_1") + assert not hasattr(rdf.results, "density_2") def test_density_zero_box(u, client_InterRDF): @@ -225,12 +207,11 @@ def test_density_zero_box(u, client_InterRDF): s1 = u.select_atoms("name OW") s2 = u.select_atoms("name HW1 HW2") rdf = InterRDF(s1, s2, norm="density").run(**client_InterRDF) - assert not hasattr(rdf.results, "density") assert hasattr(rdf.results, "box_volume") assert hasattr(rdf.results, "normalization_density") - assert hasattr(rdf.results, "density_a") - assert hasattr(rdf.results, "density_b") + assert hasattr(rdf.results, "density_1") + assert hasattr(rdf.results, "density_2") assert rdf.results.box_volume is None assert rdf.results.normalization_density is None - assert rdf.results.density_a is None - assert rdf.results.density_b is None + assert rdf.results.density_1 is None + assert rdf.results.density_2 is None diff --git a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py index f5950dbf84..6ec4ba3717 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -116,18 +116,14 @@ def test_density(u, sels, density, value, client_InterRDF_s): kwargs = {"density": density} if density is not None else {} rdf = InterRDF_s(u, sels, **kwargs).run(**client_InterRDF_s) assert_almost_equal(max(rdf.results.rdf[0][0][0]), value) - assert not hasattr(rdf.results, "density") assert hasattr(rdf.results, "box_volume") assert hasattr(rdf.results, "normalization_density") - assert rdf.results.box_volume > 0 - assert_allclose( - rdf.results.normalization_density, 1.0 / rdf.results.box_volume - ) + expected_box_vol = sum(ts.volume for ts in u.trajectory) / len(u.trajectory) + assert_allclose(rdf.results.box_volume, expected_box_vol) + assert_allclose(rdf.results.normalization_density, 1.0 / expected_box_vol) 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(**client_InterRDF_s) assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) @@ -150,9 +146,7 @@ def test_norm(u, sels, norm, value, client_InterRDF_s): 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(**client_InterRDF_s) assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) @@ -212,7 +206,6 @@ def test_density_zero_box(client_InterRDF_s): s2 = u.select_atoms("name OD1 and resid 51") ags = [[s1, s2]] rdf = InterRDF_s(u, ags, norm="density").run(**client_InterRDF_s) - assert not hasattr(rdf.results, "density") assert hasattr(rdf.results, "box_volume") assert hasattr(rdf.results, "normalization_density") assert rdf.results.box_volume is None From 436b64a6857966a80f0f858182872de9f85519f4 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Tue, 20 Oct 2026 09:41:12 +0530 Subject: [PATCH 12/13] MAINT: format with black (line-length 79) --- package/MDAnalysis/analysis/rdf.py | 10 +++++++--- testsuite/MDAnalysisTests/analysis/test_rdf.py | 4 +++- testsuite/MDAnalysisTests/analysis/test_rdf_s.py | 12 +++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index 4b7e0a8446..f09d4c0289 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -336,7 +336,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 @@ -723,7 +724,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 " @@ -737,7 +740,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/testsuite/MDAnalysisTests/analysis/test_rdf.py b/testsuite/MDAnalysisTests/analysis/test_rdf.py index 01a9dda25b..dfc84b1377 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf.py @@ -106,7 +106,9 @@ def test_exclusion(sels, client_InterRDF): assert rdf.results.count.sum() == 4 * NFRAMES -@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, client_InterRDF): # 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 6ec4ba3717..441fe4b87e 100644 --- a/testsuite/MDAnalysisTests/analysis/test_rdf_s.py +++ b/testsuite/MDAnalysisTests/analysis/test_rdf_s.py @@ -118,12 +118,16 @@ def test_density(u, sels, density, value, client_InterRDF_s): assert_almost_equal(max(rdf.results.rdf[0][0][0]), value) assert hasattr(rdf.results, "box_volume") assert hasattr(rdf.results, "normalization_density") - expected_box_vol = sum(ts.volume for ts in u.trajectory) / len(u.trajectory) + expected_box_vol = sum(ts.volume for ts in u.trajectory) / len( + u.trajectory + ) assert_allclose(rdf.results.box_volume, expected_box_vol) assert_allclose(rdf.results.normalization_density, 1.0 / expected_box_vol) 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(**client_InterRDF_s) assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) @@ -146,7 +150,9 @@ def test_norm(u, sels, norm, value, client_InterRDF_s): 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(**client_InterRDF_s) assert_almost_equal(rdf_ref.results.rdf, rdf.results.rdf[0][0][0]) From 46816ca0820d9d8c259755b0241e86705b573e77 Mon Sep 17 00:00:00 2001 From: Sumit Saraswat Date: Wed, 21 Oct 2026 08:14:34 +0530 Subject: [PATCH 13/13] DOC: update versionadded to 2.12.0 (#5362) --- package/MDAnalysis/analysis/rdf.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package/MDAnalysis/analysis/rdf.py b/package/MDAnalysis/analysis/rdf.py index f09d4c0289..902dbb7100 100644 --- a/package/MDAnalysis/analysis/rdf.py +++ b/package/MDAnalysis/analysis/rdf.py @@ -224,21 +224,21 @@ class InterRDF(AnalysisBase): :math:`N_{\text{pairs}} = N_1 N_2 - N_{\text{excl}}`. This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. - .. versionadded:: 2.11.0 + .. versionadded:: 2.12.0 results.box_volume : float The average box volume :math:`\langle V \rangle` across analyzed frames (or ``None`` if box volume is not available). This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. - .. versionadded:: 2.11.0 + .. versionadded:: 2.12.0 results.density_1 : float The bulk number density :math:`\rho_1 = N_1 / \langle V \rangle` of the first selection `g1` (or ``None`` if box volume is not available). This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. - .. versionadded:: 2.11.0 + .. versionadded:: 2.12.0 results.density_2 : float The bulk number density :math:`\rho_2 = N_2 / \langle V \rangle` of the @@ -248,7 +248,7 @@ class InterRDF(AnalysisBase): and :ref:`radial densities`. This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. - .. versionadded:: 2.11.0 + .. versionadded:: 2.12.0 Example ------- @@ -621,14 +621,14 @@ class InterRDF_s(AnalysisBase): available), where :math:`\langle V \rangle` is the average box volume. This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. - .. versionadded:: 2.11.0 + .. versionadded:: 2.12.0 results.box_volume : float The average box volume :math:`\langle V \rangle` across analyzed frames (or ``None`` if box volume is not available). This attribute only exists if `norm` is ``"rdf"`` or ``"density"``. - .. versionadded:: 2.11.0 + .. versionadded:: 2.12.0 Example -------