Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0acd3f3
clean: move pair fn logic into batched model code
CompRhys May 31, 2025
f4fa0a9
clean: begin to remove unbatched scripts
CompRhys May 31, 2025
9430e44
clean: update the dynamics scripts, remove old code, refactor the int…
CompRhys May 31, 2025
7b5413e
fix: all unit tests run
CompRhys May 31, 2025
2650dc7
fix: remove circular import
CompRhys May 31, 2025
8e2ebd9
wip: address more issues with removing unbatched code
CompRhys Jun 1, 2025
31532cb
wip: another attempt to fix examples
CompRhys Jun 1, 2025
9289748
fix: mace needs the shifts? we should add a unit test that needs them…
CompRhys Jun 1, 2025
fcb0d37
metatensor models have been renamed to metatomic models (#205)
Luthaf Jun 1, 2025
b326974
Fix discrepancies between `FIRE` optimisations in `ASE` and `torch-si…
t-reents Jun 3, 2025
68df187
bump pre-commit hooks and fix new errors
janosh Jun 3, 2025
e2330c0
fix MACE examples not using ts.io state conversion utilities
janosh Jun 3, 2025
ea41be2
fix unused shifts_list not torch.cat()-ed in mace.py
janosh Jun 6, 2025
f080b82
fix examples/scripts/3_Dynamics/3.9_MACE_NVT_staggered_stress.py usin…
janosh Jun 9, 2025
a753513
Merge branch 'main' into remove-unbatched
janosh Jun 9, 2025
f1f7b79
just calc total energy manually in nvt_langevin_invariant in torch_si…
janosh Jun 9, 2025
4d388e9
fix calculate_momenta() in npt_nose_hoover_init
janosh Jun 9, 2025
474ffa8
fix unpack of n_particles, dim = state.positions.shape
janosh Jun 9, 2025
42b1de3
fix missing external_pressure in npt_nose_hoover call in 3.8_MACE_NPT…
janosh Jun 9, 2025
2ffa79b
update cell_position in npt_nose_hoover before downstream usage
janosh Jun 9, 2025
c33794f
refactor (no bug fixes)
janosh Jun 9, 2025
31ca9ba
fix npt_nose_hoover transposing cell that's already in column-vector …
janosh Jun 9, 2025
c6cbef5
feat: Add batching support to NPT Nose-Hoover integrator
janosh Jun 9, 2025
66ebc89
fix: Remove cell dimension squeezing in NVT Nose-Hoover integrator
janosh Jun 9, 2025
4859c8d
fix: Handle scalar kT and batched stress tensors in NPT Nose-Hoover
janosh Jun 9, 2025
74cb780
fix: Handle batched cell tensors in get_fractional_coordinates
janosh Jun 9, 2025
667c4c0
replace .transpose(-2, -1) with .mT everywhere
janosh Jun 9, 2025
c09dc17
fix nvt + npt integrators: ensure consistent batch dimensions in kine…
janosh Jun 9, 2025
e7ffa3b
fix transforms.py: prevent silent data corruption in get_fractional_c…
janosh Jun 9, 2025
32397a5
fix nvt_langevin: handle None gamma parameter correctly
janosh Jun 9, 2025
a8de2e8
fix npt: missing PBC check in Nose-Hoover position update
janosh Jun 9, 2025
afda528
Initialize cur_deform_grad to prevent UnboundLocalError
janosh Jun 9, 2025
1f64641
fix nvt: compute degrees of freedom per batch in Nose-Hoover init
janosh Jun 9, 2025
334de8f
fix /5.1_a2c_silicon_batched.py: restore single-batch cell tensors su…
janosh Jun 9, 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
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ default_install_hook_types: [pre-commit, commit-msg]

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.8
rev: v0.11.12
hooks:
- id: ruff
args: [--fix]
Expand All @@ -32,7 +32,7 @@ repos:
stages: [pre-commit, commit-msg]

- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.44.0
rev: v0.45.0
hooks:
- id: markdownlint
# MD013: line length
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ final_state = ts.integrate(
n_steps=50,
timestep=0.002,
temperature=1000,
integrator=ts.nvt_langevin,
integrator=ts.integrators.nvt_langevin,
trajectory_reporter=dict(filenames=trajectory_files, state_frequency=10),
)
final_atoms_list = final_state.to_atoms()
Expand Down
2 changes: 1 addition & 1 deletion examples/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Examples are provided in two foms:

* Tutorials are intended to provide pedagogical walkthroughs of TorchSim's core functionality
* Scripts are a holdover from early torch-sim development, they are not currently recommended as a learning resource. See issue [here](https://github.com/Radical-AI/torch-sim/issues/109).
* Scripts are a holdover from early torch-sim development, they are not currently recommended as a learning resource. See issue [issue 109](https://github.com/Radical-AI/torch-sim/issues/109).

## Tutorial Formatting

Expand Down
39 changes: 2 additions & 37 deletions examples/scripts/1_Introduction/1.1_Lennard_Jones.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import torch

from torch_sim.models.lennard_jones import LennardJonesModel
from torch_sim.unbatched.models.lennard_jones import UnbatchedLennardJonesModel


# Set up the device and data type
Expand Down Expand Up @@ -61,41 +60,7 @@
# - sigma: distance at which potential is zero (3.405 Å for Ar)
# - epsilon: depth of potential well (0.0104 eV for Ar)
# - cutoff: distance beyond which interactions are ignored (typically 2.5*sigma)
model = UnbatchedLennardJonesModel(
use_neighbor_list=True,
cutoff=2.5 * 3.405,
sigma=3.405,
epsilon=0.0104,
device=device,
dtype=dtype,
compute_forces=True,
compute_stress=True,
per_atom_energies=True,
per_atom_stresses=True,
)

# Print system information
print(f"Positions: {positions.shape}")
print(f"Cell: {cell.shape}")

state = dict(
positions=positions,
cell=cell,
atomic_numbers=atomic_numbers,
pbc=True,
)
# Run the simulation and get results
results = model(state)

# Print the results
print(f"Energy: {float(results['energy']):.4f}")
print(f"Forces: {results['forces']}")
print(f"Stress: {results['stress']}")
print(f"Energies: {results['energies']}")
print(f"Stresses: {results['stresses']}")

# Batched model
batched_model = LennardJonesModel(
model = LennardJonesModel(
use_neighbor_list=True,
cutoff=2.5 * 3.405,
sigma=3.405,
Expand All @@ -117,7 +82,7 @@
)

# Run the simulation and get results
results = batched_model(state)
results = model(state)

# Print the results
print(f"Energy: {results['energy']}")
Expand Down
77 changes: 62 additions & 15 deletions examples/scripts/1_Introduction/1.2_MACE.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
"""MACE simple single system example."""
"""Minimal MACE batched example."""

# /// script
# dependencies = [
# "mace-torch>=0.3.12",
# ]
# ///

import numpy as np
import torch
from ase.build import bulk
from mace.calculators.foundations_models import mace_mp

import torch_sim as ts
from torch_sim.models.mace import MaceUrls
from torch_sim.unbatched.models.mace import UnbatchedMaceModel
from torch_sim.models.mace import MaceModel, MaceUrls


# Set device and data type
Expand All @@ -27,30 +26,78 @@
device=device,
)

# Option 2: Load from local file (comment out Option 1 to use this)
# Option 2: Load the compiled model from the local file
# MODEL_PATH = "../../../checkpoints/MACE/mace-mpa-0-medium.model"
# loaded_model = torch.load(MODEL_PATH, map_location=device)

# Create diamond cubic Silicon
si_dc = bulk("Si", "diamond", a=5.43, cubic=True).repeat((2, 2, 2))
atoms_list = [si_dc, si_dc]

# Initialize the unbatched MACE model
model = UnbatchedMaceModel(
batched_model = MaceModel(
# Pass the raw model
model=loaded_model,
# Or load from compiled model
# model=compiled_model,
device=device,
compute_forces=True,
compute_stress=True,
dtype=dtype,
enable_cueq=False,
)

# Convert ASE atoms to state
state = ts.io.atoms_to_state(si_dc, device=device, dtype=dtype)
# First we will create a concatenated positions array
# This will have shape (16, 3) which is concatenated from two 8 atom systems
positions_numpy = np.concatenate([atoms.positions for atoms in atoms_list])

# Run inference
results = model(state)
# stack cell vectors into a (2, 3, 3) array where the first index is batch dimension
cell_numpy = np.stack([atoms.cell.array for atoms in atoms_list])

# Print results
print(f"Energy: {float(results['energy']):.4f}")
print(f"Forces: {results['forces']}")
print(f"Stress: {results['stress']}")
# concatenate atomic numbers into a (16,) array
atomic_numbers_numpy = np.concatenate(
[atoms.get_atomic_numbers() for atoms in atoms_list]
)

# convert to tensors
positions = torch.tensor(positions_numpy, device=device, dtype=dtype)
cell = torch.tensor(cell_numpy, device=device, dtype=dtype)
atomic_numbers = torch.tensor(atomic_numbers_numpy, device=device, dtype=torch.int)

# create batch index array of shape (16,) which is 0 for first 8 atoms, 1 for last 8 atoms
atoms_per_batch = torch.tensor(
[len(atoms) for atoms in atoms_list], device=device, dtype=torch.int
)
batch = torch.repeat_interleave(
torch.arange(len(atoms_per_batch), device=device), atoms_per_batch
)

# You can see their shapes are as expected
print(f"Positions: {positions.shape}")
print(f"Cell: {cell.shape}")
print(f"Atomic numbers: {atomic_numbers.shape}")
print(f"Batch: {batch.shape}")

# Now we can pass them to the model
results = batched_model(
dict(
positions=positions,
cell=cell,
atomic_numbers=atomic_numbers,
batch=batch,
pbc=True,
)
)

# The energy has shape (n_batches,) as the structures in a batch
print(f"Energy: {results['energy'].shape}")

# The forces have shape (n_atoms, 3) same as positions
print(f"Forces: {results['forces'].shape}")

# The stress has shape (n_batches, 3, 3) same as cell
print(f"Stress: {results['stress'].shape}")

# Check if the energy, forces, and stress are the same for the Si system across the batch
print(torch.max(torch.abs(results["energy"][0] - results["energy"][1])))
print(torch.max(torch.abs(results["forces"][0] - results["forces"][1])))
print(torch.max(torch.abs(results["stress"][0] - results["stress"][1])))
103 changes: 0 additions & 103 deletions examples/scripts/1_Introduction/1.3_Batched_MACE.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# /// script
# dependencies = [
# "fairchem-core",
# "fairchem-core==1.10.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Use a version range for the fairchem-core dependency
Pinning to 1.10.0 ensures reproducibility, but an exact version can prevent non-critical patch updates. Consider loosening to a minor range:

-#     "fairchem-core==1.10.0",
+#     "fairchem-core>=1.10.0,<1.11.0",

Also, verify that all example scripts use a consistent fairchem-core version:


🏁 Script executed:

rg -n "fairchem-core" examples/

Length of output: 112


Loosen fairchem-core version pin

Using an exact version can block non-critical patch updates. Update to a minor-range spec that allows patch releases while staying within 1.x:

• File: examples/scripts/1_Introduction/1.3_Fairchem.py (line 6)

-    "fairchem-core==1.10.0",
+    "fairchem-core>=1.10.0,<1.11.0",

No other references to fairchem-core were found in examples/, so this change keeps all examples consistent.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In examples/scripts/1_Introduction/1.3_Fairchem.py at line 6, the fairchem-core
dependency is pinned to an exact version 1.10.0. Change this to a minor version
range, such as "fairchem-core>=1.10.0,<1.11.0", to allow patch updates while
maintaining compatibility. This ensures flexibility for non-critical updates
without breaking reproducibility.

# ]
# ///

Expand Down
Loading