Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c566129
vibecoded (need to check)
thomasloux Feb 13, 2026
4e6dccc
code for physical_validation
thomasloux Mar 24, 2026
e914b3f
vibecoded (need to check)
thomasloux Feb 13, 2026
5bf9d59
code for physical_validation
thomasloux Mar 24, 2026
275bf52
fix docs layout
thomasloux Apr 2, 2026
45d5953
remove args in docstrings that are not anymore in function args
thomasloux Apr 2, 2026
64838da
docstrings remove removed args
thomasloux Apr 2, 2026
fd3e295
- update docs to include equations
thomasloux Apr 2, 2026
f381399
Merge branch 'feat/add-physical-validation' of https://github.com/tho…
thomasloux Apr 2, 2026
349765e
remove testing files
thomasloux Apr 2, 2026
aa87925
change to strain volume equation, add a isotropic and a version with …
thomasloux Apr 3, 2026
9e25884
add test langevin_strain and update values for nose_hoover (I changed…
thomasloux Apr 3, 2026
4416122
update this test that fails on gpu because device(cuda:0) is differen…
thomasloux Apr 3, 2026
106e853
correct unwrap_positions that was wrong (because tests was wrong), er…
thomasloux Apr 3, 2026
ecabf25
update shape of test for npt_langevin variables that got changed
thomasloux Apr 3, 2026
b44a445
updated test_physical_validation
thomasloux Apr 3, 2026
aaa325d
Merge branch 'main' into feat/add-physical-validation
CompRhys Apr 4, 2026
97a552a
Merge branch 'main' into feat/add-physical-validation
CompRhys Apr 5, 2026
e8235fd
docs page to visualize integrator tests
thomasloux Apr 7, 2026
9b2250a
Merge branch 'feat/add-physical-validation' of https://github.com/tho…
thomasloux Apr 7, 2026
1fdc461
gitignore notebooks except docs/tutorials/integrator_tests_analysis.i…
thomasloux Apr 7, 2026
6cee576
rename NPT integrators in consistent way regarding isotropic, anisotr…
thomasloux Apr 8, 2026
9b1f9cd
make prek pass, remove some flags for example files and notebook as t…
thomasloux Apr 8, 2026
deb7ced
rename some help functions for Langevin and make test pass for invali…
thomasloux Apr 8, 2026
7e26367
remove gitignore local dev files
thomasloux Apr 8, 2026
587e89b
manual fixing of CI lint errors
thomasloux Apr 8, 2026
4fe8b6a
end-of-file gitignore
thomasloux Apr 8, 2026
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: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ docs/reference/torch_sim.*

# ipynb files
*.ipynb
!docs/tutorials/integrator_tests_analysis.ipynb

# ignore trajectory files
*.h5
Expand All @@ -38,6 +39,9 @@ coverage.xml
# test cache (compiled models, etc.)
tests/.cache/

# physical validation data and plots
tests/physical_validation_data/

# env
uv.lock

Expand Down
1 change: 1 addition & 0 deletions docs/tutorials/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ versions of the tutorials can also be found in the `torch-sim /examples/tutorial
hybrid_swap_tutorial
using_graphpes_tutorial
metatomic_tutorial
integrator_tests_analysis
1,420 changes: 1,420 additions & 0 deletions docs/tutorials/integrator_tests_analysis.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/user/reproducibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ sim_state.rng = 42 # required for reproducibility — torch.manual_seed() has n

### Deterministic vs stochastic integrators in TorchSim

- `ts.Integrator.nvt_langevin` and `ts.Integrator.npt_langevin` include stochastic
- `ts.Integrator.nvt_langevin` and `ts.Integrator.npt_langevin_anisotropic` include stochastic
terms by design. When seeded via `state.rng`, they produce identical trajectories.
The `rng` generator controls **both** the initial momenta sampling **and** all per-step stochastic noise (Langevin OU noise, V-Rescale draws, C-Rescale barostat noise, etc.). It is stored on the state and automatically advances on every step, so running the same seed twice produces identical trajectories.
- `ts.Integrator.nvt_nose_hoover` and `ts.Integrator.nve` are deterministic at the
Expand Down
2 changes: 1 addition & 1 deletion examples/benchmarking/opt-throughput.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def run_ase_optimization(
atoms = adaptor.get_atoms(Structure.from_dict(struct_dict))
atoms.calc = calculator
system: Any = cell_filter_cls(atoms) if cell_filter_cls is not None else atoms
opt = ase_optimizer_cls(system, logfile=os.devnull) # type: ignore[arg-type]
opt = ase_optimizer_cls(system, logfile=os.devnull)
opt.run(fmax=f_max, steps=max_steps)
if opt.get_number_of_steps() < max_steps:
converged += 1
Expand Down
16 changes: 10 additions & 6 deletions examples/scripts/3_dynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@
target_pressure = torch.tensor(0.0 * Units.pressure, device=device, dtype=dtype) # 0 bar

# Initialize NPT with NVT equilibration
state = ts.npt_nose_hoover_init(
state = ts.npt_nose_hoover_isotropic_init(
state=state, model=mace_model_stress, kT=kT, dt=torch.tensor(dt)
)

Expand All @@ -337,12 +337,14 @@
/ Units.temperature
)
invariant = float(
ts.npt_nose_hoover_invariant(state, kT=kT, external_pressure=target_pressure)
ts.npt_nose_hoover_isotropic_invariant(
state, kT=kT, external_pressure=target_pressure
)
)
log.info(
f"Step {step}: Temperature: {temp.item():.4f} K, Invariant: {invariant:.4f}"
)
state = ts.npt_nose_hoover_step(
state = ts.npt_nose_hoover_isotropic_step(
state=state,
model=mace_model_stress,
dt=torch.tensor(dt),
Expand All @@ -351,7 +353,7 @@
)

# Reinitialize for NPT phase
state = ts.npt_nose_hoover_init(
state = ts.npt_nose_hoover_isotropic_init(
state=state, model=mace_model_stress, kT=kT, dt=torch.tensor(dt)
)

Expand All @@ -365,7 +367,9 @@
/ Units.temperature
)
invariant = float(
ts.npt_nose_hoover_invariant(state, kT=kT, external_pressure=target_pressure)
ts.npt_nose_hoover_isotropic_invariant(
state, kT=kT, external_pressure=target_pressure
)
)
stress = mace_model_stress(state)["stress"]
volume = torch.det(state.current_cell)
Expand All @@ -379,7 +383,7 @@
f"Pressure: {pressure:.4f} eV/ų, "
f"Cell: [{xx.item():.4f}, {yy.item():.4f}, {zz.item():.4f}]"
)
state = ts.npt_nose_hoover_step(
state = ts.npt_nose_hoover_isotropic_step(
state=state,
model=mace_model_stress,
dt=torch.tensor(dt),
Expand Down
28 changes: 24 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies = [
[project.optional-dependencies]
test = [
"torch-sim-atomistic[io,symmetry,vesin]",
"physical-validation>=1.0.5",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: This package seems unsupported

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I believe that's the last version on pypi and it's working on my computer. What is supposed to be unsupported?

"platformdirs>=4.0.0",
"psutil>=7.0.0",
"pymatgen>=2025.6.14",
Expand Down Expand Up @@ -127,20 +128,25 @@ isort.lines-after-imports = 2
pep8-naming.ignore-names = ["get_kT", "kT"]

[tool.ruff.lint.per-file-ignores]
"**/tests/*" = ["ANN201", "D", "INP001", "S101"]
"examples/**/*" = ["B018", "T201"]
"**/tests/*" = ["ANN001", "ANN201", "ANN202", "D", "INP001", "S101", "T201"]
"examples/**/*" = ["ANN001", "ANN201", "ANN202", "B018", "T201"]
"examples/tutorials/**/*" = ["ALL"]
"docs/tutorials/*.ipynb" = ["ANN001", "ANN201", "B905", "BLE001", "E501", "F841", "N816", "PLR1714", "RUF001", "T201"]

[tool.ruff.format]
docstring-code-format = true

[tool.codespell]
check-filenames = true
ignore-words-list = ["convertor"] # codespell:ignore convertor
skip = "docs/tutorials/integrator_tests_analysis.ipynb"

[tool.pytest.ini_options]
addopts = ["-p no:warnings"]
addopts = ["-p no:warnings", "-m not physical_validation"]
testpaths = ["tests"]
markers = [
"physical_validation: long-running physical validation tests (run with: pytest -m physical_validation)",
]

[tool.uv]
# make these dependencies mutually exclusive since they use incompatible e3nn versions
Expand Down Expand Up @@ -220,18 +226,32 @@ include = [
[tool.ty.overrides.rules]
unresolved-import = "ignore"

[[tool.ty.overrides]]
include = [
"torch_sim/models/dispersion.py",
"torch_sim/neighbors/vesin.py",
]
[tool.ty.overrides.rules]
invalid-argument-type = "ignore"
invalid-assignment = "ignore"

[[tool.ty.overrides]]
include = ["tests/**/*.py"]

[tool.ty.overrides.rules]
invalid-argument-type = "ignore"
invalid-assignment = "ignore"
no-matching-overload = "ignore"
unresolved-attribute = "ignore"
unresolved-import = "ignore"

[[tool.ty.overrides]]
include = ["docs/**/*.py", "examples/**/*.py"]
include = ["docs/**/*.py", "docs/**/*.ipynb", "examples/**/*.py"]
[tool.ty.overrides.rules]
invalid-argument-type = "ignore"
not-iterable = "ignore"
not-subscriptable = "ignore"
unresolved-attribute = "ignore"
unresolved-import = "ignore"


Expand Down
16 changes: 16 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@

torch.set_num_threads(4)


def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption(
"--validation-plots",
action="store_true",
default=False,
help="Save physical validation plots to tests/physical_validation_data/plots/",
)
parser.addoption(
"--clean-validation-data",
action="store_true",
default=False,
help="Delete saved physical validation data before running tests",
)


DEVICE = torch.device("cpu")
DTYPE = torch.float64

Expand Down
16 changes: 8 additions & 8 deletions tests/test_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,8 @@ def test_constraint_validation_errors(
[
("nve", FixAtoms(atom_idx=[0, 1]), 100),
("nvt_nose_hoover", FixCom([0]), 200),
("npt_langevin", FixAtoms(atom_idx=[0, 3]), 200),
("npt_nose_hoover", FixCom([0]), 200),
("npt_langevin_anisotropic", FixAtoms(atom_idx=[0, 3]), 200),
("npt_nose_hoover_isotropic", FixCom([0]), 200),
],
)
def test_integrators_with_constraints(
Expand Down Expand Up @@ -591,20 +591,20 @@ def test_integrators_with_constraints(
state = ts.nvt_nose_hoover_init(cu_sim_state, lj_model, kT=kT, dt=dt)
for _ in range(n_steps):
state = ts.nvt_nose_hoover_step(state, lj_model, dt=dt, kT=kT)
elif integrator == "npt_langevin":
state = ts.npt_langevin_init(cu_sim_state, lj_model, kT=kT, dt=dt)
elif integrator == "npt_langevin_anisotropic":
state = ts.npt_langevin_anisotropic_init(cu_sim_state, lj_model, kT=kT, dt=dt)
for _ in range(n_steps):
state = ts.npt_langevin_step(
state = ts.npt_langevin_anisotropic_step(
state,
lj_model,
dt=dt,
kT=kT,
external_pressure=torch.tensor(0.0, dtype=DTYPE),
)
else: # npt_nose_hoover
state = ts.npt_nose_hoover_init(cu_sim_state, lj_model, kT=kT, dt=dt)
else: # npt_nose_hoover_isotropic
state = ts.npt_nose_hoover_isotropic_init(cu_sim_state, lj_model, kT=kT, dt=dt)
for _ in range(n_steps):
state = ts.npt_nose_hoover_step(
state = ts.npt_nose_hoover_isotropic_step(
state,
lj_model,
dt=torch.tensor(0.001, dtype=DTYPE),
Expand Down
4 changes: 2 additions & 2 deletions tests/test_fix_symmetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,9 +539,9 @@ def test_build_symmetry_map_chunked_matches_vectorized() -> None:

old_threshold = sym_mod._SYMM_MAP_CHUNK_THRESHOLD # noqa: SLF001
try:
sym_mod._SYMM_MAP_CHUNK_THRESHOLD = len(state.positions) + 1 # noqa: SLF001 # ty: ignore[invalid-assignment]
sym_mod._SYMM_MAP_CHUNK_THRESHOLD = len(state.positions) + 1 # noqa: SLF001
vectorized = build_symmetry_map(rotations, translations, frac)
sym_mod._SYMM_MAP_CHUNK_THRESHOLD = 0 # noqa: SLF001 # ty: ignore[invalid-assignment]
sym_mod._SYMM_MAP_CHUNK_THRESHOLD = 0 # noqa: SLF001
chunked = build_symmetry_map(rotations, translations, frac)
finally:
sym_mod._SYMM_MAP_CHUNK_THRESHOLD = old_threshold # noqa: SLF001
Expand Down
Loading
Loading