Simulations with TorchSim#

TorchSim is a GPU-accelerated molecular simulation engine built on PyTorch. MatterSim provides a TorchSimWrapper that adapts MatterSim potentials as a TorchSim ModelInterface, so you can use TorchSim’s optimizers and integrators directly with MatterSim models.

Creating a TorchSim wrapper#

The easiest way to create a wrapper is via the get_torchsim_wrapper helper, which accepts a model identifier, a checkpoint path, or an already-loaded Potential object.

 1import torch
 2from mattersim.torchsim import get_torchsim_wrapper
 3
 4device = "cuda" if torch.cuda.is_available() else "cpu"
 5
 6# From a model identifier (downloads the checkpoint automatically)
 7wrapper = get_torchsim_wrapper(potential="mattersim-v1.0.0-1M", device=device)
 8
 9# Or from an already-loaded Potential
10from mattersim.forcefield import Potential
11
12potential = Potential.from_checkpoint(device=device)
13wrapper = get_torchsim_wrapper(potential=potential, device=device)

You can also construct the wrapper directly if you need full control:

1from mattersim.torchsim import TorchSimWrapper
2from mattersim.forcefield import Potential
3
4potential = Potential.from_checkpoint(device=device)
5wrapper = TorchSimWrapper(model=potential, device=device)

Structure relaxation#

TorchSim provides several optimizers for structure relaxation, including fire, lbfgs, bfgs, and gradient_descent.

 1import numpy as np
 2import torch
 3import torch_sim as ts
 4from ase.build import bulk
 5from mattersim.torchsim import get_torchsim_wrapper
 6
 7device = "cuda" if torch.cuda.is_available() else "cpu"
 8
 9# Create the wrapper
10wrapper = get_torchsim_wrapper(potential="mattersim-v1.0.0-1M", device=device)
11
12# Set up the structure
13si = bulk("Si", "diamond", a=5.43)
14si.positions += 0.1 * np.random.randn(len(si), 3)
15
16# Initialize a TorchSim state from the ASE Atoms object
17state = ts.initialize_state([si], device=device)
18
19# Run relaxation with the FIRE optimizer
20relaxed_state = ts.optimize(
21    system=state,
22    model=wrapper,
23    optimizer=ts.Optimizer.fire,
24    max_steps=500,
25    pbar=True,
26)
27
28# Convert back to ASE Atoms
29relaxed_atoms = relaxed_state.to_atoms()[0]
30print(f"Relaxed energy: {relaxed_state.energy[0].item():.4f} eV")

You can also customize convergence criteria using ts.generate_force_convergence_fn:

 1convergence_fn = ts.generate_force_convergence_fn(force_tol=0.01)
 2
 3relaxed_state = ts.optimize(
 4    system=state,
 5    model=wrapper,
 6    optimizer=ts.Optimizer.fire,
 7    max_steps=500,
 8    convergence_fn=convergence_fn,
 9    pbar=True,
10)

Molecular dynamics#

TorchSim supports various integrators for molecular dynamics simulations. Below we demonstrate NVT dynamics using a Langevin thermostat.

 1import torch
 2import torch_sim as ts
 3from ase.build import bulk
 4from mattersim.torchsim import get_torchsim_wrapper
 5
 6device = "cuda" if torch.cuda.is_available() else "cpu"
 7
 8# Create the wrapper
 9wrapper = get_torchsim_wrapper(potential="mattersim-v1.0.0-1M", device=device)
10
11# Set up the structure
12si = bulk("Si", "diamond", a=5.43)
13state = ts.initialize_state([si], device=device)
14
15# Run NVT MD at 300 K for 1000 steps
16final_state = ts.integrate(
17    system=state,
18    model=wrapper,
19    integrator=ts.Integrator.nvt_langevin,
20    n_steps=1000,
21    temperature=300.0,
22    timestep=1e-3,
23    pbar=True,
24)
25
26# Convert back to ASE Atoms
27final_atoms = final_state.to_atoms()[0]

Available integrators include:

  • NVE: ts.Integrator.nve — microcanonical ensemble

  • NVT Langevin: ts.Integrator.nvt_langevin — Langevin thermostat

  • NVT Nosé–Hoover: ts.Integrator.nvt_nose_hoover — Nosé–Hoover thermostat

  • NPT Langevin: ts.Integrator.npt_langevin_isotropic — Langevin barostat (isotropic)

  • NPT Nosé–Hoover: ts.Integrator.npt_nose_hoover_isotropic — Nosé–Hoover barostat (isotropic)

Saving trajectories#

TorchSim can save trajectory frames to HDF5 files during the simulation using a TrajectoryReporter.

 1import torch
 2import torch_sim as ts
 3from ase.build import bulk
 4from mattersim.torchsim import get_torchsim_wrapper
 5
 6device = "cuda" if torch.cuda.is_available() else "cpu"
 7wrapper = get_torchsim_wrapper(potential="mattersim-v1.0.0-1M", device=device)
 8
 9si = bulk("Si", "diamond", a=5.43)
10state = ts.initialize_state([si], device=device)
11
12# Configure a trajectory reporter to save every 100 steps
13reporter = ts.TrajectoryReporter(
14    filenames=["md_trajectory.h5md"],
15    state_frequency=100,
16    state_kwargs=dict(save_velocities=True, save_forces=True),
17)
18
19final_state = ts.integrate(
20    system=state,
21    model=wrapper,
22    integrator=ts.Integrator.nvt_langevin,
23    n_steps=1000,
24    temperature=300.0,
25    timestep=1e-3,
26    trajectory_reporter=reporter,
27    pbar=True,
28)

Note

For more details on TorchSim’s API, including autobatching, advanced trajectory handling, and custom integrators, please refer to the TorchSim documentation.