Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7a6b97d
Added recipoe for simple descriptors calculation.
matteobecchi Jul 1, 2025
80bc4a0
Added recipe on PCA.
matteobecchi Jul 2, 2025
237baa9
Added recipe for TICA.
matteobecchi Jul 2, 2025
64b0eb5
Added recipe for tSOAP.
matteobecchi Jul 2, 2025
a7b1aad
Code improved; added function to compute or load soap in utilities.
matteobecchi Jul 2, 2025
a8cbf3e
Some improvements in docs.
matteobecchi Jul 2, 2025
5d92f87
Improved code readibility.
matteobecchi Jul 2, 2025
10f3960
WIP on the third recipe.
matteobecchi Jul 3, 2025
8a6c354
WIP for info_gain recipe.
matteobecchi Jul 3, 2025
91f6450
Logging class implemented.
matteobecchi Jul 3, 2025
05d6fdc
Added logging to Trj class.
matteobecchi Jul 3, 2025
27d0e81
Added deeptime dependecies.
matteobecchi Jul 3, 2025
aee3046
Logging added to Insight methods.
matteobecchi Jul 4, 2025
2b3ead3
Added pytests for logging.
matteobecchi Jul 4, 2025
b34f93b
deeptime dependecies is now automatically installed.
matteobecchi Jul 4, 2025
e2395a9
deeptime dependecies is now automatically installed.
matteobecchi Jul 4, 2025
d470bf8
Explicitly saing 'is not None' for file paths.
matteobecchi Jul 7, 2025
e929dfe
Using standard dictionary for logging args in method calls.
matteobecchi Jul 7, 2025
ff2c3bb
Logging added to the ClusterInsight classes.
matteobecchi Jul 7, 2025
aba2279
Error raising added to logging.
matteobecchi Jul 7, 2025
e597fb4
WIP on third recipe.
matteobecchi Jul 8, 2025
818fe54
Adding a page of documentation for dynsight.trajectory.
matteobecchi Jul 9, 2025
93bf483
WIP on the third recipe.
matteobecchi Jul 9, 2025
9963146
v1 of third recipe working; cleaned file names.
matteobecchi Jul 9, 2025
a674388
Added info_plot function to third recipe.
matteobecchi Jul 9, 2025
bf2bbb4
Minor adjustments.
matteobecchi Jul 9, 2025
9c2778f
Dataset changed for maningful results.
matteobecchi Jul 9, 2025
14b21dd
Added description of fig.
matteobecchi Jul 9, 2025
e0e197c
Added Trj.n_atoms, Trj.n_frames.
matteobecchi Jul 9, 2025
7de8040
Added warnings on directories.
matteobecchi Jul 17, 2025
d710b02
Minor improvements.
matteobecchi Jul 17, 2025
af0b828
All the imports at the top.
matteobecchi Jul 17, 2025
14886f9
Solving typos.
matteobecchi Jul 17, 2025
dd284c4
Minor improvements.
matteobecchi Jul 17, 2025
d08fc47
Improved code explanation.
matteobecchi Jul 17, 2025
51724ad
Improved code explanation.
matteobecchi Jul 17, 2025
6f3e647
Added how to get started section in docs.
matteobecchi Jul 17, 2025
82a1e6f
Solving mypy problems.
matteobecchi Jul 17, 2025
e545635
Added downloadable script from recipes.
matteobecchi Jul 17, 2025
1a439e8
Removing useless mypy stuff.
matteobecchi Jul 17, 2025
d41e46f
Solving mypy issue.
matteobecchi Jul 17, 2025
36f52f2
Solving mypy issue for real.
matteobecchi Jul 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,18 @@ you are using Python 3.10 and below, you can use ``cpctools`` to access

$ pip install cpctools

If you want to use the ``dynsight.tica`` module you will need to install the
Comment thread
matteobecchi marked this conversation as resolved.
deeptime package. This can be done with with pip::

$ pip install deeptime

or with conda::

$ conda install -c conda-forge deeptime

If you want to use the ``dynsight.vision`` and ``dynsight.track`` modules
you will need to install a series of packages. This can be done with with pip::

$ pip install ultralytics PyYAML

How to get started
------------------

We suggest you give a read to the ``dynsight.trajectory`` module documentation,
which offers a compact and easy way of using most of the ``dynsight`` tools.
Also, the documentation offers some copiable Recipes and Examples for the most
common analyses.

How to contribute
-----------------
Expand Down
Binary file added docs/source/_static/info_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/source/_static/recipes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Copyable code for the recipes."""
50 changes: 50 additions & 0 deletions docs/source/_static/recipes/descr_from_trj.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Copiable code from Recipe #1."""

from pathlib import Path

from dynsight.trajectory import Trj


def main() -> None:
"""Code from the Recipe #1."""
# Loading an example trajectory
files_path = Path("../tests/systems/")
trj = Trj.init_from_xtc(
traj_file=files_path / "balls_7_nvt.xtc",
topo_file=files_path / "balls_7_nvt.gro",
)

_ = trj.get_soap(
r_cut=2.0, # cutoff radius for neighbors list
n_max=4, # n_max SOAP parameter
l_max=4, # l_max SOAP parameter
selection="all", # compute on a selection of particles
centers="all", # compute for a selection of centers
respect_pbc=False, # consider PBC
n_core=1, # use multiprocessing to speed up calculations
)

# Loading an example trajectory
files_path = Path("../tests/systems/")
trj = Trj.init_from_xtc(
traj_file=files_path / "balls_7_nvt.xtc",
topo_file=files_path / "balls_7_nvt.gro",
)

# Computing number of neighbors from scratch
neigcounts, n_neig = trj.get_coord_number(
r_cut=2.0, # cutoff radius for neighbors list
selection="all", # compute on a selection of particles
neigcounts=None, # it will be computed and returned
)

# Now for LENS we already have neigcounts
_, lens = trj.get_lens(
r_cut=2.0, # cutoff radius for neighbors list
selection="all", # compute on a selection of particles
neigcounts=neigcounts, # no need to compute it again
)


if __name__ == "__main__":
main()
179 changes: 179 additions & 0 deletions docs/source/_static/recipes/info_gain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
"""Copiable code from Recipe #3."""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from numpy.typing import NDArray

import matplotlib.pyplot as plt
import numpy as np

import dynsight


def info_gain_with_onion(
delta_t_list: NDArray[np.int64] | list[int],
data: NDArray[np.float64],
n_bins: int = 40,
) -> tuple[
NDArray[np.int64],
NDArray[np.float64],
NDArray[np.float64],
NDArray[np.float64],
float,
]:
"""Performs full information gain analysis with Onion clustering."""
data_range = (np.min(data), np.max(data))

n_clusters = np.zeros(len(delta_t_list), dtype=int)
clusters_frac = []
info_gain = np.zeros(len(delta_t_list))
clusters_entr = []

for i, delta_t in enumerate(delta_t_list):
state_list, labels = dynsight.onion.onion_uni_smooth(
data,
delta_t=delta_t,
)

n_clusters[i] = len(state_list)
tmp_frac = [0.0] + [state.perc for state in state_list]
tmp_frac[0] = 1.0 - np.sum(tmp_frac)
clusters_frac.append(tmp_frac)

flat_data = data.flatten()
flat_labels = labels.flatten()
info_gain[i], _, h_0, _ = dynsight.analysis.compute_entropy_gain(
flat_data,
flat_labels,
n_bins=n_bins,
)

tmp_entr = []
label_list = np.unique(labels)
if label_list[0] != -1:
tmp_entr.append(-1.0)

for _, lab in enumerate(label_list):
mask = labels == lab
selected_points = data[mask]
tmp_entr.append(
dynsight.analysis.compute_shannon(
selected_points,
data_range,
n_bins=n_bins,
)
)
clusters_entr.append(tmp_entr)

max_n_envs = np.max([len(elem) for elem in clusters_entr])
for i, elem in enumerate(clusters_entr):
while len(elem) < max_n_envs:
elem.append(-1.0)
clusters_frac[i].append(0.0)

cl_frac = np.array(clusters_frac, dtype=float)
cl_entr = np.array(clusters_entr)

return n_clusters, cl_frac, info_gain, cl_entr, h_0


def plot_info_results(
delta_t_list: NDArray[np.int64] | list[int],
cl_frac: NDArray[np.float64],
cl_entr: NDArray[np.float64],
h_0: float,
file_path: Path,
) -> None:
"""Plot information gain as a function of ∆t."""
frac = cl_frac.T
entr = cl_entr.T
s_list = []
for i, st_fr in enumerate(frac):
s_list.append(st_fr * entr[i])
s_cumul = [s_list[0]]
for _, tmp_s in enumerate(s_list[1:]):
s_cumul.append(s_cumul[-1] + tmp_s)

fig, ax = plt.subplots()

i_0 = (1 - h_0) * np.ones(len(delta_t_list))
ax.plot(delta_t_list, i_0, ls="--", c="black", marker="") # I_0
ax.fill_between(
delta_t_list,
1,
1 - s_cumul[0],
alpha=0.5,
)
for i, tmp_s in enumerate(s_cumul[1:]):
ax.fill_between(
delta_t_list,
1 - s_cumul[i],
1 - tmp_s,
alpha=0.5,
)
ax.fill_between(
delta_t_list,
1 - s_cumul[-1],
1 - h_0,
color="gainsboro",
)
ax.plot(
delta_t_list,
1 - s_cumul[-1],
c="black",
marker="",
) # I_clust

ax.set_ylim(0.0, 1.0)
ax.set_xlabel(r"Time resolution $\Delta t$")
ax.set_ylabel(r"Information $I$")
ax.set_xscale("log")

fig.savefig(file_path, dpi=600)
plt.close()


def main() -> None:
"""Copiable code from Recipe #3."""
rng = np.random.default_rng(1234)

n_atoms = 10
num_blocks = 10
block_size = 100
sigma = 0.1

# Generate the array
tmp_data = [
np.concatenate(
[
rng.normal(loc=(i % 2), scale=sigma, size=block_size)
for i in range(num_blocks)
]
)
for _ in range(n_atoms)
]
data = np.array(tmp_data)

_, n_frames = data.shape
delta_t_list = np.unique(np.geomspace(2, n_frames, 10, dtype=int))

n_cl, cl_frac, info_gain, cl_entr, h_0 = info_gain_with_onion(
delta_t_list,
data,
)

plot_info_results(
delta_t_list,
cl_frac,
cl_entr,
h_0,
Path("./source/_static/info_plot.png"),
)


if __name__ == "__main__":
main()
Loading
Loading