Skip to content

Commit 86cff98

Browse files
Feature: Correlation function module (#115)
* [FEATURE]: Implements time-series correlation calculator. This is done using circular buffer for data storage and FFT-based method for correlation functions. Test suit on idealized signals created and passing. * Update status, expose module to docs * Update doc-string * Update link * Example script using correlations module for VACF. * Update module docstring * Git blame used for metadata, addresses: - #115 (comment) - #115 (comment) * Refactor: - Addresses #115 (comment) - Addresses #115 (comment) * Refactor: #115 (comment) * Improves design, where correlation step now defined by call. See #115 (comment) clean-ups ase well * Addresses #115 (comment) * feat: add VelocityAutoCorrelation class and test. See #115 (comment) * refactor: use in example. See #115 (review) --------- Co-authored-by: Orion Cohen <[email protected]>
1 parent 66c5feb commit 86cff98

File tree

6 files changed

+1101
-0
lines changed

6 files changed

+1101
-0
lines changed

docs/reference/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This section gives an overview of the API for torch_sim.
1313
:nosignatures:
1414

1515
autobatching
16+
properties.correlations
1617
elastic
1718
io
1819
math
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"""Velocity autocorrelation example."""
2+
3+
# /// script
4+
# dependencies = [
5+
# "ase>=3.24",
6+
# "matplotlib",
7+
# "numpy",
8+
# ]
9+
# ///
10+
11+
from typing import Any
12+
13+
import matplotlib.pyplot as plt
14+
import numpy as np
15+
import torch
16+
from ase.build import bulk
17+
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
18+
19+
import torch_sim as ts
20+
from torch_sim.models.lennard_jones import LennardJonesModel
21+
from torch_sim.properties.correlations import VelocityAutoCorrelation
22+
from torch_sim.units import MetalUnits as Units
23+
24+
25+
def prepare_system() -> tuple[
26+
Any, Any, torch.Tensor, torch.Tensor, torch.device, torch.dtype, float
27+
]:
28+
"""Create and prepare Ar system with LJ potential."""
29+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
30+
dtype = torch.float64
31+
32+
# Using solid Ar w/ LJ for ease
33+
atoms = bulk("Ar", crystalstructure="fcc", a=5.256, cubic=True)
34+
atoms = atoms.repeat((3, 3, 3))
35+
temperature = 50.0 # Kelvin
36+
MaxwellBoltzmannDistribution(atoms, temperature_K=temperature)
37+
state = ts.io.atoms_to_state(atoms, device=device, dtype=dtype)
38+
39+
epsilon = 0.0104 # eV
40+
sigma = 3.4 # Å
41+
cutoff = 2.5 * sigma
42+
43+
lj_model = LennardJonesModel(
44+
sigma=sigma,
45+
epsilon=epsilon,
46+
cutoff=cutoff,
47+
device=device,
48+
dtype=dtype,
49+
compute_forces=True,
50+
)
51+
52+
timestep = 0.001 # ps (1 fs)
53+
dt = torch.tensor(timestep * Units.time, device=device, dtype=dtype)
54+
temp_kT = temperature * Units.temperature # Convert K to internal units
55+
kT = torch.tensor(temp_kT, device=device, dtype=dtype)
56+
57+
return state, lj_model, dt, kT, device, dtype, timestep
58+
59+
60+
def plot_results(*, time: np.ndarray, vacf: np.ndarray, window_count: int) -> None:
61+
"""Plot VACF results."""
62+
plt.figure(figsize=(10, 8))
63+
plt.plot(time, vacf, "b-", linewidth=2)
64+
plt.xlabel("Time (fs)", fontsize=12)
65+
plt.ylabel("VACF", fontsize=12)
66+
plt.title(f"VACF (Average of {window_count} windows)", fontsize=14)
67+
plt.axhline(y=0, color="k", linestyle="--", alpha=0.3)
68+
plt.ylim(-0.6, 1.1)
69+
plt.tight_layout()
70+
plt.savefig("vacf_example.png")
71+
72+
73+
def main() -> None:
74+
"""Run velocity autocorrelation simulation using Lennard-Jones model."""
75+
state, lj_model, dt, kT, device, dtype, timestep = prepare_system()
76+
nve_init, nve_update = ts.integrators.nve(model=lj_model, dt=dt, kT=kT)
77+
state = nve_init(state) # type: ignore[call-arg]
78+
79+
window_size = 150 # Length of correlation: dt * correlation_dt * window_size
80+
vacf_calc = VelocityAutoCorrelation(
81+
window_size=window_size,
82+
device=device,
83+
use_running_average=True,
84+
normalize=True,
85+
)
86+
87+
# Sampling freq is controlled by prop_calculators
88+
trajectory = "vacf_example.h5"
89+
correlation_dt = 10 # Step delta between correlations
90+
reporter = ts.TrajectoryReporter(
91+
trajectory,
92+
state_frequency=100,
93+
prop_calculators={correlation_dt: {"vacf": vacf_calc}},
94+
)
95+
96+
num_steps = 15000 # NOTE: short run
97+
for step in range(num_steps):
98+
state = nve_update(state) # type: ignore[call-arg]
99+
reporter.report(state, step)
100+
101+
reporter.close()
102+
103+
# VACF results and plot
104+
# Timesteps -> Time in fs
105+
time_steps = np.arange(window_size)
106+
time = time_steps * correlation_dt * timestep * 1000
107+
108+
if vacf_calc.vacf is not None:
109+
plot_results(
110+
time=time,
111+
vacf=vacf_calc.vacf.cpu().numpy(),
112+
# Just for demo purposes
113+
window_count=vacf_calc._window_count, # noqa: SLF001
114+
)
115+
116+
117+
if __name__ == "__main__":
118+
main()

0 commit comments

Comments
 (0)