Skip to content

Commit 054f174

Browse files
orionarcherjanosh
andcommitted
Finalize readme, docs, and coverage (#100 - #104)
* plot speedup * change import line * conf.py docs fix * restyle TorchSim -> torch-sim * small typo fix * tweak err messages * small trajectory fix and ignore unbatched in codecov * remove seemingly unneeded Structure/Atoms/PhonopyAtoms stubs in torch_sim/io.py * set coverage target * fix toml * multi line string * tweak doc strings * switch away from .png * move speedup up in readme * fix broken links and set threshold differently * docs fix * delete codevoc threshhold attempt --------- Co-authored-by: Janosh Riebesell <[email protected]>
1 parent 3242452 commit 054f174

File tree

12 files changed

+121
-149
lines changed

12 files changed

+121
-149
lines changed
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"ignorePatterns": [
3-
{
4-
"pattern": "../tutorials/.+.ipynb$"
5-
}
3+
{"pattern": "../tutorials/.+.ipynb$"},
4+
{"pattern": "*github.com/user-attachments*"}
65
]
76
}

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ repos:
2222
- id: check-case-conflict
2323
- id: check-symlinks
2424
- id: check-yaml
25-
exclude: ".*\/copilot\/.*"
25+
exclude: .*\/copilot\/.*
2626
- id: destroyed-symlinks
2727
- id: end-of-file-fixer
2828
- id: forbid-new-submodules
@@ -34,7 +34,7 @@ repos:
3434
hooks:
3535
- id: codespell
3636
stages: [pre-commit, commit-msg]
37-
args: ["--ignore-words-list", "statics,crate,annote,atomate,nd,te,titel,coo,slite,fro"]
37+
args: [--ignore-words-list, "statics,crate,annote,atomate,nd,te,titel,coo,slite,fro"]
3838

3939
- repo: https://github.com/igorshubovych/markdownlint-cli
4040
rev: v0.44.0

README.md

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
[![CI](https://github.com/radical-ai/torch-sim/actions/workflows/test.yml/badge.svg)](https://github.com/radical-ai/torch-sim/actions/workflows/test.yml)
44
[![codecov](https://codecov.io/gh/radical-ai/torch-sim/branch/main/graph/badge.svg)](https://codecov.io/gh/radical-ai/torch-sim)
55
[![This project supports Python 3.11+](https://img.shields.io/badge/Python-3.11+-blue.svg?logo=python&logoColor=white)](https://python.org/downloads)
6-
[![PyPI](https://img.shields.io/pypi/v/torch-sim?logo=pypi&logoColor=white)](https://pypi.org/project/torch-sim)
6+
[![PyPI](https://img.shields.io/pypi/v/torch_sim_atomistic?logo=pypi&logoColor=white)](https://pypi.org/project/torch_sim_atomistic)
77
[![Zenodo](https://img.shields.io/badge/Zenodo-15127004-blue?logo=Zenodo&logoColor=white)][zenodo]
88

99
[zenodo]: https://zenodo.org/records/15127004
1010

1111
<!-- help docs find start of prose in readme, DO NOT REMOVE -->
12-
TorchSim is an next-generation open-source atomistic simulation engine for the MLIP era. By rewriting the core primitives of atomistic simulation in Pytorch, it allows orders of magnitude acceleration of popular machine learning potentials.
12+
torch-sim is a next-generation open-source atomistic simulation engine for the MLIP
13+
era. By rewriting the core primitives of atomistic simulation in Pytorch, it allows
14+
orders of magnitude acceleration of popular machine learning potentials.
1315

1416
* Automatic batching and GPU memory management allowing significant simulation speedup
15-
* Support for MACE and Fairchem MLIP models
17+
* Support for MACE, Fairchem, and SevenNet MLIP models with more in progress
1618
* Support for classical lennard jones, morse, and soft-sphere potentials
17-
* Molecular dynamics integration schemes like NVE, NVT Langevin, and NPT langevin
19+
* Molecular dynamics integration schemes like NVE, NVT Langevin, and NPT Langevin
1820
* Relaxation of atomic positions and cell with gradient descent and FIRE
1921
* Swap monte carlo and hybrid swap monte carlo algorithm
2022
* An extensible binary trajectory writing format with support for arbitrary properties
@@ -24,7 +26,7 @@ TorchSim is an next-generation open-source atomistic simulation engine for the M
2426

2527
## Quick Start
2628

27-
Here is a quick demonstration of many of the core features of TorchSim:
29+
Here is a quick demonstration of many of the core features of torch-sim:
2830
native support for GPUs, MLIP models, ASE integration, simple API,
2931
autobatching, and trajectory reporting, all in under 40 lines of code.
3032

@@ -85,12 +87,25 @@ relaxed_state = ts.optimize(
8587
print(relaxed_state.energy)
8688
```
8789

90+
## Speedup
91+
92+
torch-sim achieves up to 100x speedup compared to ASE with popular MLIPs.
93+
94+
![Speedup comparison](https://github.com/user-attachments/assets/2ad1d8b0-a7aa-467b-9260-acb76a1ed591)
95+
96+
This figure compares the time per atom of ASE and torch_sim. Time per atom is defined
97+
as the number of atoms / total time. While ASE can only run a single system of n_atoms
98+
(on the x axis), torch_sim can run as many systems as will fit in memory. On an H100,
99+
the max atoms that could fit in memory was 8000 for gemnet, 10000 for MACE, and 2500
100+
for SevenNet. This metric describes model performance by capturing speed and memory
101+
usage simultaneously.
102+
88103
## Installation
89104

90105
### PyPI Installation
91106

92107
```sh
93-
pip install torch-sim
108+
pip install torch-sim-atomistic
94109
```
95110

96111
### Installing from source
@@ -103,18 +118,18 @@ pip install .
103118

104119
## Examples
105120

106-
To understand how `torch-sim` works, start with the [comprehensive tutorials](https://radical-ai.github.io/torch-sim/user/overview.html) in the documentation.
121+
To understand how torch-sim works, start with the [comprehensive tutorials](https://radical-ai.github.io/torch-sim/user/overview.html) in the documentation.
107122

108123
Even more usage examples can be found in the [`examples/`](examples/readme.md) folder.
109124

110125
## Core Modules
111126

112-
The `torch-sim` structured is summarized in the [API reference](https://radical-ai.github.io/torch-sim/reference/index.html) documentation.
127+
torch-sim's structure is summarized in the [API reference](https://radical-ai.github.io/torch-sim/reference/index.html) documentation.
113128

114129
## License
115130

116131
`torch-sim` is released under an [MIT license](LICENSE).
117132

118133
## Citation
119134

120-
A manuscript is in preparation. Meanwhile, if you use TorchSim in your research, please [cite the Zenodo archive][zenodo].
135+
A manuscript is in preparation. Meanwhile, if you use torch-sim in your research, please [cite the Zenodo archive][zenodo].

docs/conf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717

1818
# -- Project information -----------------------------------------------------
1919

20-
project = "torch-sim"
20+
project = "torch-sim-atomistic"
2121
copyright = "2025, Radical AI" # noqa: A001
2222
author = "Abhijeet Gangan, Orion Cohen, Janosh Riebesell"
2323

2424
# The short X.Y version
25-
version = importlib.metadata.version("torch-sim")
25+
version = importlib.metadata.version(project)
2626
# The full version, including alpha/beta/rc tags
27-
release = importlib.metadata.version("torch-sim")
27+
release = importlib.metadata.version(project)
2828

2929
# -- General configuration ---------------------------------------------------
3030

docs/dev/dev_install.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ python -m http.server -d docs_build
8181
To locally generate the tutorials, they must be copied to the docs folder,
8282
converted to `.ipynb` files, and executed. Then the .py files and any generated
8383
trajectory files must be cleaned up.
84+
8485
```bash
8586
cp -r examples/tutorials docs/ && \
8687
jupytext --set-formats "py:percent,ipynb" docs/tutorials/*.py && \

docs/user/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ Learn more in [Understanding Reporting](../tutorials/reporting_tutorial.ipynb)
2929

3030
Under the hood, `torch-sim` takes a modular functional approach to atomistic simulation. Each integrator or optimizer function, such as `nvt_langevin,` takes in a model and parameters and returns `init` and `update` functions that act on a unique `State.` The state inherits from `SimState` and tracks the fixed and fluctuating parameters of the simulation, such as the `momenta` for NVT or the timestep for FIRE. The runner functions take this basic structure and wrap it in a convenient interface with autobatching and reporting.
3131

32-
Learn more in [Fundamentals of `torch-sim`](../tutorials/low_level_tutorial.ipynb) and [Hybrid Swap Tutorial](../tutorials/hybrid_swap_tutorial.ipynb)
32+
Learn more in [Fundamentals of `torch-sim`](../tutorials/low_level_tutorial.ipynb) and [Implementing New Methods](../tutorials/hybrid_swap_tutorial.ipynb)

pyproject.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[project]
2-
name = "torch_sim"
2+
name = "torch_sim_atomistic"
33
version = "0.1.0"
44
description = "A pytorch toolkit for calculating material properties using MLIPs"
55
authors = [
@@ -87,6 +87,7 @@ ignore = [
8787
"ERA001", # Found commented-out code
8888
"FIX002", # Line contains TODO, consider resolving the issue
8989
"G003", # logging-string-concat
90+
"G004", # logging uses f-string
9091
"INP001", # implicit-namespace-package
9192
"ISC001", # avoid conflicts with the formatter
9293
"N803", # Variable name should be lowercase
@@ -118,7 +119,6 @@ pep8-naming.ignore-names = ["get_kT", "kT"]
118119
"examples/**/*" = ["B018"]
119120
"examples/tutorials/**/*" = ["ALL"]
120121

121-
122122
[tool.ruff.format]
123123
docstring-code-format = true
124124

@@ -128,3 +128,8 @@ check-filenames = true
128128
[tool.pytest]
129129
addopts = ["--cov-report=term-missing", "--cov=torch_sim", "-v"]
130130
testpaths = ["tests"]
131+
132+
[tool.coverage.run]
133+
omit = [
134+
"torch_sim/unbatched/*",
135+
]

tests/test_trajectory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,12 +354,12 @@ def test_invalid_dtype_handling(test_file: Path) -> None:
354354
complex_data = {
355355
"complex": np.random.default_rng(seed=0).random((10, 3)).astype(np.float16)
356356
}
357-
with pytest.raises(ValueError, match="Unsupported dtype"):
357+
with pytest.raises(ValueError, match="Unsupported array.dtype="):
358358
traj.write_arrays(complex_data, steps=0)
359359

360360
# Test string data
361361
string_data = {"strings": np.array([["a", "b", "c"]] * 10)}
362-
with pytest.raises(ValueError, match="Unsupported dtype"):
362+
with pytest.raises(ValueError, match="Unsupported array.dtype="):
363363
traj.write_arrays(string_data, steps=0)
364364

365365
traj.close()

torch_sim/autobatching.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -86,36 +86,36 @@ def _argmax_bins(lst: list[float]) -> int:
8686
def _revargsort_bins(lst: list[float]) -> list[int]:
8787
return sorted(range(len(lst)), key=lambda i: -lst[i])
8888

89-
isdict = isinstance(items, dict)
89+
is_dict = isinstance(items, dict)
9090

9191
if not hasattr(items, "__len__"):
9292
raise TypeError("d must be iterable")
9393

94-
if not isdict and hasattr(items[0], "__len__"):
94+
if not is_dict and hasattr(items[0], "__len__"):
9595
if weight_pos is not None:
9696
key = lambda x: x[weight_pos] # noqa: E731
9797
if key is None:
9898
raise ValueError("Must provide weight_pos or key for tuple list")
9999

100-
if not isdict and key:
100+
if not is_dict and key:
101101
new_dict = dict(enumerate(items))
102102
items = {i: key(val) for i, val in enumerate(items)}
103-
isdict = True
103+
is_dict = True
104104
is_tuple_list = True
105105
else:
106106
is_tuple_list = False
107107

108-
if isdict:
108+
if is_dict:
109109
# get keys and values (weights)
110110
keys_vals = items.items()
111111
keys = [k for k, v in keys_vals]
112112
vals = [v for k, v in keys_vals]
113113

114114
# sort weights decreasingly
115-
ndcs = _revargsort_bins(vals)
115+
n_dcs = _revargsort_bins(vals)
116116

117-
weights = _get_bins(vals, ndcs)
118-
keys = _get_bins(keys, ndcs)
117+
weights = _get_bins(vals, n_dcs)
118+
keys = _get_bins(keys, n_dcs)
119119

120120
bins = [{}]
121121
else:
@@ -140,15 +140,15 @@ def _revargsort_bins(lst: list[float]) -> list[int]:
140140

141141
weights = _get_bins(weights, valid_ndcs)
142142

143-
if isdict:
143+
if is_dict:
144144
keys = _get_bins(keys, valid_ndcs)
145145

146146
# prepare array containing the current weight of the bins
147147
weight_sum = [0.0]
148148

149149
# iterate through the weight list, starting with heaviest
150150
for item, weight in enumerate(weights):
151-
if isdict:
151+
if is_dict:
152152
key = keys[item]
153153

154154
# find candidate bins where the weight might fit
@@ -170,7 +170,7 @@ def _revargsort_bins(lst: list[float]) -> list[int]:
170170
# open a new bin
171171
b = len(weight_sum)
172172
weight_sum.append(0.0)
173-
if isdict:
173+
if is_dict:
174174
bins.append({})
175175
else:
176176
bins.append([])
@@ -180,7 +180,7 @@ def _revargsort_bins(lst: list[float]) -> list[int]:
180180
b = 0
181181

182182
# put it in
183-
if isdict:
183+
if is_dict:
184184
bins[b][key] = weight
185185
else:
186186
bins[b].append(weight)
@@ -234,9 +234,7 @@ def measure_model_memory_forward(state: SimState, model: ModelInterface) -> floa
234234

235235
logging.info( # noqa: LOG015
236236
"Model Memory Estimation: Running forward pass on state with "
237-
"%s atoms and %s batches.",
238-
state.n_atoms,
239-
state.n_batches,
237+
f"{state.n_atoms} atoms and {state.n_batches} batches.",
240238
)
241239
# Clear GPU memory
242240
torch.cuda.synchronize()
@@ -324,7 +322,7 @@ def calculate_memory_scaler(
324322
Args:
325323
state (SimState): State to calculate metric for, with shape information
326324
specific to the SimState instance.
327-
memory_scales_with (Literal["n_atoms_x_density", "n_atoms"]): Type of metric
325+
memory_scales_with ("n_atoms_x_density" |s "n_atoms"): Type of metric
328326
to use. "n_atoms" uses only atom count and is suitable for models that
329327
have a fixed number of neighbors. "n_atoms_x_density" uses atom count
330328
multiplied by number density and is better for models with radial cutoffs
@@ -404,12 +402,9 @@ def estimate_max_memory_scaler(
404402

405403
logging.info( # noqa: LOG015
406404
"Model Memory Estimation: Estimating memory from worst case of "
407-
"largest and smallest system. Largest system has %s atoms and %s batches, "
408-
"and smallest system has %s atoms and %s batches.",
409-
max_state.n_atoms,
410-
max_state.n_batches,
411-
min_state.n_atoms,
412-
min_state.n_batches,
405+
f"largest and smallest system. Largest system has {max_state.n_atoms} atoms "
406+
f"and {max_state.n_batches} batches, and smallest system has "
407+
f"{min_state.n_atoms} atoms and {min_state.n_batches} batches.",
413408
)
414409
min_state_max_batches = determine_max_batch_size(min_state, model, **kwargs)
415410
max_state_max_batches = determine_max_batch_size(max_state, model, **kwargs)
@@ -474,7 +469,7 @@ def __init__(
474469
Args:
475470
model (ModelInterface): Model to batch for, used to estimate memory
476471
requirements.
477-
memory_scales_with (Literal["n_atoms", "n_atoms_x_density"]): Metric to use
472+
memory_scales_with ("n_atoms" | "n_atoms_x_density"): Metric to use
478473
for estimating memory requirements:
479474
- "n_atoms": Uses only atom count
480475
- "n_atoms_x_density": Uses atom count multiplied by number density
@@ -767,7 +762,7 @@ def __init__(
767762
Args:
768763
model (ModelInterface): Model to batch for, used to estimate memory
769764
requirements.
770-
memory_scales_with (Literal["n_atoms", "n_atoms_x_density"]): Metric to use
765+
memory_scales_with ("n_atoms" | "n_atoms_x_density"): Metric to use
771766
for estimating memory requirements:
772767
- "n_atoms": Uses only atom count
773768
- "n_atoms_x_density": Uses atom count multiplied by number density

0 commit comments

Comments
 (0)