From 32b550012bda07d551d97ea969f97723b19efeda Mon Sep 17 00:00:00 2001 From: "Anastasia K. Lavrinenko" <75916717+AstyLavrinenko@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:38:42 +0200 Subject: [PATCH 1/6] Add RDFs calculation based on species not transitions information Currently, the RDFs can be calculated for floating species, requiring sites data or transition information. Could you please additionally implement a version that calculates RDFs between specified species without the need for transition data. I have provided the code we use for this calculation, which includes parallelization. --- src/gemdat/rdf.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/gemdat/rdf.py b/src/gemdat/rdf.py index 0dae7636..cc303f0a 100644 --- a/src/gemdat/rdf.py +++ b/src/gemdat/rdf.py @@ -185,3 +185,41 @@ def radial_distribution( ret[state].append(rdf_data) return ret + + + +import matplotlib.pyplot as plt +import numpy as np +from joblib import Parallel, delayed + +def calculate_rdf_parallelized(trajectory, specie_1, specie_2, resolution=1, max_distance=10.0): + '''Calculate RDFs from specie_1 to specie_2''' + coords_1 = trajectory.filter(specie_1).coords + coords_2 = trajectory.filter(specie_2).coords + lattice = trajectory.get_lattice() + + try: + num_time_steps, num_atoms, num_dimensions = coords_2.shape + except ValueError: + num_time_steps = 1 + num_atoms, num_dimensions = coords_2.shape + + particle_vol = num_atoms / ((4 / 3) * np.pi * max_distance ** 3) + + def calculate_distances(t): + return lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) + + all_dists = Parallel(n_jobs=-1)(delayed(calculate_distances)(t) for t in range(num_time_steps)) + distances = np.concatenate([dists[dists != 0].flatten() for dists in all_dists]) + + bins = np.arange(0, max_distance + resolution, resolution) + rdf, _ = np.histogram(distances, bins=bins, density=False) + + norm = np.array([(4 / 3) * np.pi * ((r + resolution) ** 3 - r ** 3) * particle_vol for r in bins[:-1]]) + rdf = np.array([rdf[i] / norm[i] for i in range(len(rdf))]) + + return bins, rdf + + +bins, rdf = calculate_rdf_parallelized(trajectory=trajectory, specie_1='Li', specie_2=['S','Cl'], resolution=0.1, max_distance=10) +plt.plot(bins[:-1], rdf) From a852705e6fada5f3c8589f41a30d697dc40a1778 Mon Sep 17 00:00:00 2001 From: "Anastasia K. Lavrinenko" <75916717+AstyLavrinenko@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:19:00 +0200 Subject: [PATCH 2/6] Update rdf.py --- src/gemdat/rdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gemdat/rdf.py b/src/gemdat/rdf.py index cc303f0a..6a5abb62 100644 --- a/src/gemdat/rdf.py +++ b/src/gemdat/rdf.py @@ -204,7 +204,7 @@ def calculate_rdf_parallelized(trajectory, specie_1, specie_2, resolution=1, max num_time_steps = 1 num_atoms, num_dimensions = coords_2.shape - particle_vol = num_atoms / ((4 / 3) * np.pi * max_distance ** 3) + particle_vol = num_atoms / lattice.volume def calculate_distances(t): return lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) From 966e4a7b0595d34f7d77eb6fb9dc7739187a3bf5 Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Mon, 11 Nov 2024 15:10:35 +0100 Subject: [PATCH 3/6] Refactor rdf between species --- src/gemdat/rdf.py | 79 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/src/gemdat/rdf.py b/src/gemdat/rdf.py index 6a5abb62..2cb47d8c 100644 --- a/src/gemdat/rdf.py +++ b/src/gemdat/rdf.py @@ -4,14 +4,19 @@ from dataclasses import dataclass from typing import TYPE_CHECKING +import matplotlib.pyplot as plt import numpy as np from rich.progress import track from ._plot_backend import plot_backend if TYPE_CHECKING: + from typing import Collection + + import matplotlib.figure from pymatgen.core import Structure + from gemdat import Trajectory from gemdat.transitions import Transitions @@ -187,39 +192,69 @@ def radial_distribution( return ret +def plot_rdf_between_species( + trajectory: Trajectory, + specie_1: str | Collection[str], + specie_2: str | Collection[str], + max_dist: float = 5.0, + resolution: float = 0.1, +) -> matplotlib.figure.Figure: + """Calculate RDFs from specie_1 to specie_2. -import matplotlib.pyplot as plt -import numpy as np -from joblib import Parallel, delayed + Parameters + ---------- + trajectory: Trajectory + Input trajectory. + specie_1: str | list[str] + Name of specie or list of species + specie_2: str | list[str] + Name of specie or list of species + max_dist: float, optional + Max distance for rdf calculation + resolution: float, optional + Width of the bins -def calculate_rdf_parallelized(trajectory, specie_1, specie_2, resolution=1, max_distance=10.0): - '''Calculate RDFs from specie_1 to specie_2''' + Returns + ------- + fig : matplotlib.figure.Figure + Output figure + """ coords_1 = trajectory.filter(specie_1).coords coords_2 = trajectory.filter(specie_2).coords lattice = trajectory.get_lattice() - try: - num_time_steps, num_atoms, num_dimensions = coords_2.shape - except ValueError: + if coords_2.ndim == 2: num_time_steps = 1 num_atoms, num_dimensions = coords_2.shape + else: + num_time_steps, num_atoms, num_dimensions = coords_2.shape particle_vol = num_atoms / lattice.volume - def calculate_distances(t): - return lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) + all_dists = np.concatenate( + [ + lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) + for t in range(num_time_steps) + ] + ) + distances = all_dists.flatten() - all_dists = Parallel(n_jobs=-1)(delayed(calculate_distances)(t) for t in range(num_time_steps)) - distances = np.concatenate([dists[dists != 0].flatten() for dists in all_dists]) - - bins = np.arange(0, max_distance + resolution, resolution) + bins = np.arange(0, max_dist + resolution, resolution) rdf, _ = np.histogram(distances, bins=bins, density=False) - norm = np.array([(4 / 3) * np.pi * ((r + resolution) ** 3 - r ** 3) * particle_vol for r in bins[:-1]]) - rdf = np.array([rdf[i] / norm[i] for i in range(len(rdf))]) - - return bins, rdf - - -bins, rdf = calculate_rdf_parallelized(trajectory=trajectory, specie_1='Li', specie_2=['S','Cl'], resolution=0.1, max_distance=10) -plt.plot(bins[:-1], rdf) + def normalize(radius: np.ndarray) -> np.ndarray: + """Normalize bin to volume.""" + shell = (radius + resolution) ** 3 - radius**3 + return particle_vol * (4 / 3) * np.pi * shell + + norm = normalize(bins)[:-1] + rdf = rdf / norm + + fig, ax = plt.subplots() + ax.plot(bins[:-1], rdf) + ax.set( + title=f'RDF between {specie_1} and {specie_2} per element', + xlabel='Displacement (Å)', + ylabel='Nr. of atoms', + ) + return fig From da2ba48cbe3d55ebcb0600f44d7a974e92383c00 Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Mon, 11 Nov 2024 15:32:55 +0100 Subject: [PATCH 4/6] Move plotting code and add boilerplate for plotly --- src/gemdat/plots/__init__.py | 2 + src/gemdat/plots/matplotlib/__init__.py | 2 + .../_radial_distribution_between_species.py | 81 +++++++++++++++++++ src/gemdat/plots/plotly/__init__.py | 3 +- .../_radial_distribution_between_species.py | 41 ++++++++++ src/gemdat/rdf.py | 73 ----------------- src/gemdat/trajectory.py | 6 ++ 7 files changed, 134 insertions(+), 74 deletions(-) create mode 100644 src/gemdat/plots/matplotlib/_radial_distribution_between_species.py create mode 100644 src/gemdat/plots/plotly/_radial_distribution_between_species.py diff --git a/src/gemdat/plots/__init__.py b/src/gemdat/plots/__init__.py index 5374af03..edb86f91 100644 --- a/src/gemdat/plots/__init__.py +++ b/src/gemdat/plots/__init__.py @@ -21,6 +21,7 @@ msd_per_element, plot_3d, radial_distribution, + radial_distribution_between_species, rectilinear, shape, vibrational_amplitudes, @@ -44,6 +45,7 @@ 'msd_per_element', 'plot_3d', 'radial_distribution', + 'radial_distribution_between_species', 'rectilinear', 'shape', 'vibrational_amplitudes', diff --git a/src/gemdat/plots/matplotlib/__init__.py b/src/gemdat/plots/matplotlib/__init__.py index d364361d..f66e507d 100644 --- a/src/gemdat/plots/matplotlib/__init__.py +++ b/src/gemdat/plots/matplotlib/__init__.py @@ -17,6 +17,7 @@ from ._jumps_vs_time import jumps_vs_time from ._msd_per_element import msd_per_element from ._radial_distribution import radial_distribution +from ._radial_distribution_between_species import radial_distribution_between_species from ._rectilinear import rectilinear from ._shape import shape from ._vibrational_amplitudes import vibrational_amplitudes @@ -36,6 +37,7 @@ 'jumps_vs_time', 'msd_per_element', 'radial_distribution', + 'radial_distribution_between_species', 'rectilinear', 'shape', 'vibrational_amplitudes', diff --git a/src/gemdat/plots/matplotlib/_radial_distribution_between_species.py b/src/gemdat/plots/matplotlib/_radial_distribution_between_species.py new file mode 100644 index 00000000..fd0a6442 --- /dev/null +++ b/src/gemdat/plots/matplotlib/_radial_distribution_between_species.py @@ -0,0 +1,81 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import matplotlib.pyplot as plt +import numpy as np + +if TYPE_CHECKING: + from typing import Collection + + import matplotlib.figure + + from gemdat import Trajectory + + +def radial_distribution_between_species( + trajectory: Trajectory, + specie_1: str | Collection[str], + specie_2: str | Collection[str], + max_dist: float = 5.0, + resolution: float = 0.1, +) -> matplotlib.figure.Figure: + """Calculate RDFs from specie_1 to specie_2. + + Parameters + ---------- + trajectory: Trajectory + Input trajectory. + specie_1: str | list[str] + Name of specie or list of species + specie_2: str | list[str] + Name of specie or list of species + max_dist: float, optional + Max distance for rdf calculation + resolution: float, optional + Width of the bins + + Returns + ------- + fig : matplotlib.figure.Figure + Output figure + """ + coords_1 = trajectory.filter(specie_1).coords + coords_2 = trajectory.filter(specie_2).coords + lattice = trajectory.get_lattice() + + if coords_2.ndim == 2: + num_time_steps = 1 + num_atoms, num_dimensions = coords_2.shape + else: + num_time_steps, num_atoms, num_dimensions = coords_2.shape + + particle_vol = num_atoms / lattice.volume + + all_dists = np.concatenate( + [ + lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) + for t in range(num_time_steps) + ] + ) + distances = all_dists.flatten() + + bins = np.arange(0, max_dist + resolution, resolution) + rdf, _ = np.histogram(distances, bins=bins, density=False) + + def normalize(radius: np.ndarray) -> np.ndarray: + """Normalize bin to volume.""" + shell = (radius + resolution) ** 3 - radius**3 + return particle_vol * (4 / 3) * np.pi * shell + + norm = normalize(bins)[:-1] + rdf = rdf / norm + + fig, ax = plt.subplots() + ax.plot(bins[:-1], rdf) + ax.set( + title=f'RDF between {specie_1} and {specie_2} per element', + xlabel='Displacement (Å)', + ylabel='Nr. of atoms', + ) + return fig diff --git a/src/gemdat/plots/plotly/__init__.py b/src/gemdat/plots/plotly/__init__.py index 6cafdf25..afc852fd 100644 --- a/src/gemdat/plots/plotly/__init__.py +++ b/src/gemdat/plots/plotly/__init__.py @@ -17,6 +17,7 @@ from ._msd_per_element import msd_per_element from ._plot3d import plot_3d from ._radial_distribution import radial_distribution +from ._radial_distribution_between_species import radial_distribution_between_species from ._rectilinear import rectilinear from ._shape import shape from ._vibrational_amplitudes import vibrational_amplitudes @@ -32,12 +33,12 @@ 'energy_along_path', 'frequency_vs_occurence', 'jumps_3d', - 'jumps_3d_animation', 'jumps_vs_distance', 'jumps_vs_time', 'msd_per_element', 'plot_3d', 'radial_distribution', + 'radial_distribution_between_species', 'rectilinear', 'shape', 'vibrational_amplitudes', diff --git a/src/gemdat/plots/plotly/_radial_distribution_between_species.py b/src/gemdat/plots/plotly/_radial_distribution_between_species.py new file mode 100644 index 00000000..e6008870 --- /dev/null +++ b/src/gemdat/plots/plotly/_radial_distribution_between_species.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import plotly.graph_objects as go + +if TYPE_CHECKING: + from typing import Collection + + from gemdat import Trajectory + + +def radial_distribution_between_species( + trajectory: Trajectory, + specie_1: str | Collection[str], + specie_2: str | Collection[str], + max_dist: float = 5.0, + resolution: float = 0.1, +) -> go.Figure: + """Calculate RDFs from specie_1 to specie_2. + + Parameters + ---------- + trajectory: Trajectory + Input trajectory. + specie_1: str | list[str] + Name of specie or list of species + specie_2: str | list[str] + Name of specie or list of species + max_dist: float, optional + Max distance for rdf calculation + resolution: float, optional + Width of the bins + + Returns + ------- + fig : matplotlib.figure.Figure + Output figure + """ + fig = go.Figure() + raise NotImplementedError diff --git a/src/gemdat/rdf.py b/src/gemdat/rdf.py index 2cb47d8c..0dae7636 100644 --- a/src/gemdat/rdf.py +++ b/src/gemdat/rdf.py @@ -4,19 +4,14 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -import matplotlib.pyplot as plt import numpy as np from rich.progress import track from ._plot_backend import plot_backend if TYPE_CHECKING: - from typing import Collection - - import matplotlib.figure from pymatgen.core import Structure - from gemdat import Trajectory from gemdat.transitions import Transitions @@ -190,71 +185,3 @@ def radial_distribution( ret[state].append(rdf_data) return ret - - -def plot_rdf_between_species( - trajectory: Trajectory, - specie_1: str | Collection[str], - specie_2: str | Collection[str], - max_dist: float = 5.0, - resolution: float = 0.1, -) -> matplotlib.figure.Figure: - """Calculate RDFs from specie_1 to specie_2. - - Parameters - ---------- - trajectory: Trajectory - Input trajectory. - specie_1: str | list[str] - Name of specie or list of species - specie_2: str | list[str] - Name of specie or list of species - max_dist: float, optional - Max distance for rdf calculation - resolution: float, optional - Width of the bins - - Returns - ------- - fig : matplotlib.figure.Figure - Output figure - """ - coords_1 = trajectory.filter(specie_1).coords - coords_2 = trajectory.filter(specie_2).coords - lattice = trajectory.get_lattice() - - if coords_2.ndim == 2: - num_time_steps = 1 - num_atoms, num_dimensions = coords_2.shape - else: - num_time_steps, num_atoms, num_dimensions = coords_2.shape - - particle_vol = num_atoms / lattice.volume - - all_dists = np.concatenate( - [ - lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) - for t in range(num_time_steps) - ] - ) - distances = all_dists.flatten() - - bins = np.arange(0, max_dist + resolution, resolution) - rdf, _ = np.histogram(distances, bins=bins, density=False) - - def normalize(radius: np.ndarray) -> np.ndarray: - """Normalize bin to volume.""" - shell = (radius + resolution) ** 3 - radius**3 - return particle_vol * (4 / 3) * np.pi * shell - - norm = normalize(bins)[:-1] - rdf = rdf / norm - - fig, ax = plt.subplots() - ax.plot(bins[:-1], rdf) - ax.set( - title=f'RDF between {specie_1} and {specie_2} per element', - xlabel='Displacement (Å)', - ylabel='Nr. of atoms', - ) - return fig diff --git a/src/gemdat/trajectory.py b/src/gemdat/trajectory.py index 5d6cf414..20200046 100644 --- a/src/gemdat/trajectory.py +++ b/src/gemdat/trajectory.py @@ -758,6 +758,12 @@ def plot_frequency_vs_occurence(self, *, module, **kwargs): """See [gemdat.plots.frequency_vs_occurence][] for more info.""" return module.frequency_vs_occurence(trajectory=self, **kwargs) + @plot_backend + def plot_radial_distribution_between_species(self, *, module, **kwargs): + """See [gemdat.plots.radial_distribution_between_species][] for more + info.""" + return module.vibrational_amplitudes(trajectory=self, **kwargs) + @plot_backend def plot_vibrational_amplitudes(self, *, module, **kwargs): """See [gemdat.plots.vibrational_amplitudes][] for more info.""" From 1c05b04772cefef1e09fa1850d06047e24f45032 Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Mon, 11 Nov 2024 15:43:56 +0100 Subject: [PATCH 5/6] Add test for matplotlib version --- src/gemdat/trajectory.py | 2 +- .../radial_distribution_between_species.png | Bin 0 -> 17801 bytes tests/integration/plot_mpl_test.py | 8 ++++++++ tests/integration/plot_plotly_test.py | 11 +++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/integration/baseline_images/plot_mpl_test/radial_distribution_between_species.png diff --git a/src/gemdat/trajectory.py b/src/gemdat/trajectory.py index 20200046..71ba5fdd 100644 --- a/src/gemdat/trajectory.py +++ b/src/gemdat/trajectory.py @@ -762,7 +762,7 @@ def plot_frequency_vs_occurence(self, *, module, **kwargs): def plot_radial_distribution_between_species(self, *, module, **kwargs): """See [gemdat.plots.radial_distribution_between_species][] for more info.""" - return module.vibrational_amplitudes(trajectory=self, **kwargs) + return module.radial_distribution_between_species(trajectory=self, **kwargs) @plot_backend def plot_vibrational_amplitudes(self, *, module, **kwargs): diff --git a/tests/integration/baseline_images/plot_mpl_test/radial_distribution_between_species.png b/tests/integration/baseline_images/plot_mpl_test/radial_distribution_between_species.png new file mode 100644 index 0000000000000000000000000000000000000000..0a8df3854c10fe52adf005eb789a69c5d3b8ef34 GIT binary patch literal 17801 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≺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 Bcn<&o literal 0 HcmV?d00001 diff --git a/tests/integration/plot_mpl_test.py b/tests/integration/plot_mpl_test.py index d3caf617..5eee168c 100644 --- a/tests/integration/plot_mpl_test.py +++ b/tests/integration/plot_mpl_test.py @@ -75,6 +75,14 @@ def test_radial_distribution(vasp_rdf_data): rdfs.plot(backend=BACKEND) +@image_comparison2(baseline_images=['radial_distribution_between_species']) +def test_radial_distribution_between_species(vasp_traj): + traj = vasp_traj[-500:] + traj.plot_radial_distribution_between_species( + backend=BACKEND, specie_1='Li', specie_2=('S', 'CL') + ) + + @image_comparison2(baseline_images=['shape']) def test_shape(vasp_shape_data): assert len(vasp_shape_data) == 1 diff --git a/tests/integration/plot_plotly_test.py b/tests/integration/plot_plotly_test.py index a37d277d..64723b74 100644 --- a/tests/integration/plot_plotly_test.py +++ b/tests/integration/plot_plotly_test.py @@ -74,6 +74,17 @@ def test_radial_distribution(vasp_rdf_data): assert_figures_similar(fig, name=f'radial_distribution_{i}', rms=0.5) +def test_radial_distribution_between_species(vasp_traj): + traj = vasp_traj[-500:] + fig = traj.plot_radial_distribution_between_species( + backend=BACKEND, + specie_1='Li', + specie_2=('S', 'CL'), + ) + + assert_figures_similar(fig, name='radial_distribution_between_species', rms=0.5) + + def test_shape(vasp_shape_data): assert len(vasp_shape_data) == 1 for shape in vasp_shape_data: From 5ee293d6d9a73ae54720bc415bddf51da5132cdb Mon Sep 17 00:00:00 2001 From: Stef Smeets Date: Mon, 11 Nov 2024 15:59:39 +0100 Subject: [PATCH 6/6] Add plotly version --- src/gemdat/plots/_shared.py | 44 +++++++++++++++++ .../_radial_distribution_between_species.py | 45 +++++------------- .../_radial_distribution_between_species.py | 27 ++++++++++- .../radial_distribution_between_species.png | Bin 17801 -> 16753 bytes .../radial_distribution_between_species.png | Bin 0 -> 37679 bytes 5 files changed, 83 insertions(+), 33 deletions(-) create mode 100644 tests/integration/baseline_images/plot_plotly_test/radial_distribution_between_species.png diff --git a/src/gemdat/plots/_shared.py b/src/gemdat/plots/_shared.py index ec3f427b..f97e02bb 100644 --- a/src/gemdat/plots/_shared.py +++ b/src/gemdat/plots/_shared.py @@ -10,6 +10,8 @@ from scipy.stats import skewnorm if TYPE_CHECKING: + from typing import Collection + from gemdat.orientations import Orientations from gemdat.trajectory import Trajectory @@ -147,3 +149,45 @@ def _get_vibrational_amplitudes_hist( std = np.std(data, axis=0) return VibrationalAmplitudeHist(amplitudes=amplitudes, counts=mean, std=std) + + +def _get_radial_distribution_between_species( + *, + trajectory: Trajectory, + specie_1: str | Collection[str], + specie_2: str | Collection[str], + max_dist: float = 5.0, + resolution: float = 0.1, +) -> tuple[np.ndarray, np.ndarray]: + coords_1 = trajectory.filter(specie_1).coords + coords_2 = trajectory.filter(specie_2).coords + lattice = trajectory.get_lattice() + + if coords_2.ndim == 2: + num_time_steps = 1 + num_atoms, num_dimensions = coords_2.shape + else: + num_time_steps, num_atoms, num_dimensions = coords_2.shape + + particle_vol = num_atoms / lattice.volume + + all_dists = np.concatenate( + [ + lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) + for t in range(num_time_steps) + ] + ) + distances = all_dists.flatten() + + bins = np.arange(0, max_dist + resolution, resolution) + rdf, _ = np.histogram(distances, bins=bins, density=False) + + def normalize(radius: np.ndarray) -> np.ndarray: + """Normalize bin to volume.""" + shell = (radius + resolution) ** 3 - radius**3 + return particle_vol * (4 / 3) * np.pi * shell + + norm = normalize(bins)[:-1] + rdf = rdf / norm + + return bins, rdf diff --git a/src/gemdat/plots/matplotlib/_radial_distribution_between_species.py b/src/gemdat/plots/matplotlib/_radial_distribution_between_species.py index fd0a6442..ea6b2203 100644 --- a/src/gemdat/plots/matplotlib/_radial_distribution_between_species.py +++ b/src/gemdat/plots/matplotlib/_radial_distribution_between_species.py @@ -3,7 +3,8 @@ from typing import TYPE_CHECKING import matplotlib.pyplot as plt -import numpy as np + +from .._shared import _get_radial_distribution_between_species if TYPE_CHECKING: from typing import Collection @@ -14,6 +15,7 @@ def radial_distribution_between_species( + *, trajectory: Trajectory, specie_1: str | Collection[str], specie_2: str | Collection[str], @@ -40,42 +42,21 @@ def radial_distribution_between_species( fig : matplotlib.figure.Figure Output figure """ - coords_1 = trajectory.filter(specie_1).coords - coords_2 = trajectory.filter(specie_2).coords - lattice = trajectory.get_lattice() - - if coords_2.ndim == 2: - num_time_steps = 1 - num_atoms, num_dimensions = coords_2.shape - else: - num_time_steps, num_atoms, num_dimensions = coords_2.shape - - particle_vol = num_atoms / lattice.volume - - all_dists = np.concatenate( - [ - lattice.get_all_distances(coords_1[t, :, :], coords_2[t, :, :]) - for t in range(num_time_steps) - ] + bins, rdf = _get_radial_distribution_between_species( + trajectory=trajectory, + specie_1=specie_1, + specie_2=specie_2, + max_dist=max_dist, + resolution=resolution, ) - distances = all_dists.flatten() - - bins = np.arange(0, max_dist + resolution, resolution) - rdf, _ = np.histogram(distances, bins=bins, density=False) - - def normalize(radius: np.ndarray) -> np.ndarray: - """Normalize bin to volume.""" - shell = (radius + resolution) ** 3 - radius**3 - return particle_vol * (4 / 3) * np.pi * shell - - norm = normalize(bins)[:-1] - rdf = rdf / norm fig, ax = plt.subplots() ax.plot(bins[:-1], rdf) + str1 = specie_1 if isinstance(specie_1, str) else ' / '.join(specie_1) + str2 = specie_1 if isinstance(specie_2, str) else ' / '.join(specie_2) ax.set( - title=f'RDF between {specie_1} and {specie_2} per element', - xlabel='Displacement (Å)', + title=f'RDF between {str1} and {str2}', + xlabel='Radius (Å)', ylabel='Nr. of atoms', ) return fig diff --git a/src/gemdat/plots/plotly/_radial_distribution_between_species.py b/src/gemdat/plots/plotly/_radial_distribution_between_species.py index e6008870..f4f6816e 100644 --- a/src/gemdat/plots/plotly/_radial_distribution_between_species.py +++ b/src/gemdat/plots/plotly/_radial_distribution_between_species.py @@ -4,6 +4,8 @@ import plotly.graph_objects as go +from .._shared import _get_radial_distribution_between_species + if TYPE_CHECKING: from typing import Collection @@ -37,5 +39,28 @@ def radial_distribution_between_species( fig : matplotlib.figure.Figure Output figure """ + bins, rdf = _get_radial_distribution_between_species( + trajectory=trajectory, + specie_1=specie_1, + specie_2=specie_2, + max_dist=max_dist, + resolution=resolution, + ) + fig = go.Figure() - raise NotImplementedError + fig.add_trace( + go.Scatter( + x=bins, + y=rdf, + name='Radial distribution', + mode='lines', + ) + ) + str1 = specie_1 if isinstance(specie_1, str) else ' / '.join(specie_1) + str2 = specie_1 if isinstance(specie_2, str) else ' / '.join(specie_2) + fig.update_layout( + title=f'RDF between {str1} and {str2}', + xaxis_title='Radius (Å)', + yaxis_title='Nr. of atoms', + ) + return fig diff --git a/tests/integration/baseline_images/plot_mpl_test/radial_distribution_between_species.png b/tests/integration/baseline_images/plot_mpl_test/radial_distribution_between_species.png index 0a8df3854c10fe52adf005eb789a69c5d3b8ef34..c177e655284212049bf33dd42129c46ff836cdc9 100644 GIT binary patch literal 16753 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 U=mz|!3K*s=uYNV>$}Ru@1_09wy#N3J literal 17801 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≺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 Bcn<&o diff --git a/tests/integration/baseline_images/plot_plotly_test/radial_distribution_between_species.png b/tests/integration/baseline_images/plot_plotly_test/radial_distribution_between_species.png new file mode 100644 index 0000000000000000000000000000000000000000..6b4c698303156fbf284da7029a0c687e89381892 GIT binary patch literal 37679 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
6fbzj1AcKze_2RiDhbq(e&@8A{hu~6 z3w%ft(^ro_Uh_%425@*1@sPJ*WPg1LDuDIHYdHVsYnK5JKp^`-D-k)qLBfO0nEco~ zj@*wX9hu!4`gL@<-Xh0M_YO=}<`&-U9P+&qB0k8cI~(C{@O5Dl>H9#kJy@IRFQ)5~ z1boi;!l(yd**UViamPeH;%q{%4Vfh@CNkr?v5YId6lBcQtr@tR;5svqHeql*;IwVN z5WjKJ$JTH#TFCry14buIqxo#(bwqMm!`_dgWEPdYNQU7SW#k=RF#%JcyiTo03Fe&P zG6nE)8t`cpqLajxI0p07X>>N3G_^0vBtOEANFhQ!2lV2!pK(V@YGrNk@cp zGFtXOpSlkbp~=%JCC^<5zyJO#IZ-{$g3AY+?PN%;r|MwgleUgWB4NlU(CiC7P2?!b z^&aZYDNGc4Xs-YSCtvSVO!g4S_kjy#9at~jzh9*@QtvK~5pjqG>X;=0c9v9f-K2Mx zPVU@b82GVPpWJZmt=a9?!;qN%B1Jx(D#%r>J0?(*M=eMr(znU8>0K&&b8zLGEzZ{5 zmmpV|l@CLQBHY(dwfIGcnC5$bEc|ib{n|=NA855rbuLj>PrB(_4$YG}gK;fE{pR5| zzCn+5b`PFnaX0)EVorWHk$a0XN)&)A;Wbf)ttz{-=S!-@2v&p7pwi3cgrnm~SFj+a zn0)|F-ljy^Uw(ew>ZuqxAqP=;f{Rq$(fEsR26 z7yH&s!5{4#_Tx8g9v}6< zk{TRyg*t#SU%Gme5&AkjQDXSaI7(Q_Ecx{HrNNB3YY~j|EGseWMv1A+0o^3r2wW42oN=dN4xvat>lwP|i zIqfTq?zId!e}WH@txV4@IYLejIbwNUTv}(>6NE!UVvLkC?#XHg%e`m0MkmV8a50Ub z1V7>EC{#lpSipx8S2o}b%mjq+lD8r>*hb+i#!tH7zBKt!Y_jUd4TUP(p5oux*QrO1s)4N88U8IFO41JC1pA;&7%~; z%!#y=3o@nQDhH|VY=iF2wQRoEqY8A+`4lbe4i1e(fXQ71fL?$eV92hWKzUjF ziOF*=%TAp^@AOXg=3|W=LXp!>;aJfnwBz!I++l0!{p?LhftT|RtHYF0Hr zv$76!eGqzH`91NAN@XNL$oBxHM1NXS+|mYq*Ug9n$caE@=xlIdP}HQ9tkQ_BK2gW} zq+`Ug_W4{o-|H04cCa%104>jUarbIr;N=I6hNxfGzH!+uQ3SH0Ny^KOYY`aLucni% ztX5`~Lkhx08`Pl)c#{Jox21%cd_p-6@aTiF$&C9JzgX_kR2eLX~l2W zAF&6k!q=#wwYRr%$Fra0U|(D74G1L}OObBjRfuNQ9j7@Y8MfOdY+(QKtuSEZ1_vy4 z547^E{5nLkRUJyCc%-2Z47ay1m^8jpZXvugJ$2_a)2T zCM_g4nzqI2fPY|K%fVL_TMDY(xD{=BeNzVMInV)2FQymu_vs!fp$QJ@0O$R!d2q?U zzgVCi7=QnQ{4C(k2;|kq2+027R)8~`=kGua>1KQfzKr2S9aQKKp8^GoGv(rl|LGUe z`4j<126ttBt{ZHhznu(a$RW<(zaZz256qvYE2nMv?=b;2_AawO#`u6P54bQbHSRAQ z|MbR)^~BKr{M``vFO=UWx)P8^@vpB`#1{GAzaZU%=fIX1t?R+4evc^}3eN-N$kkTiJp{{YmbxF7%k literal 0 HcmV?d00001