Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ASE tutorial #43

Merged
merged 66 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
3ea3e6a
Add gradient calculator
frostedoyster Jan 4, 2024
79d161e
Fix linter
frostedoyster Jan 4, 2024
e65679d
Loss draft
frostedoyster Jan 11, 2024
8591d7d
Add tests for losses
frostedoyster Jan 11, 2024
8df7e41
Wrap forces and stresses
frostedoyster Jan 11, 2024
0ffc0a9
Clarify cell convention
frostedoyster Jan 11, 2024
9253931
Merge branch 'main' into forces-virials
frostedoyster Jan 11, 2024
9b93eaa
Support multiple model outputs, use new loss
frostedoyster Jan 11, 2024
83c94e6
Fix composition calculator
frostedoyster Jan 11, 2024
4f1c569
Address review
frostedoyster Jan 12, 2024
7c32d9e
Partial draft
frostedoyster Jan 12, 2024
3081a0f
Finished trainer
frostedoyster Jan 12, 2024
ed8697f
Make linter happy
frostedoyster Jan 12, 2024
589b586
Merge branch 'main' into finalize-training
frostedoyster Jan 13, 2024
01a528b
Fix small merge issue
frostedoyster Jan 12, 2024
aa31433
Add new functions to the documentation
frostedoyster Jan 16, 2024
9061f1c
Add tutorial how to override arch params
PicoCentauri Jan 18, 2024
631d274
Adapt to most recent parser changes
frostedoyster Jan 19, 2024
dc523b7
Train with actual train/validation splits
frostedoyster Jan 19, 2024
fe0bd01
Fix some small issues
frostedoyster Jan 19, 2024
f579652
Merge branch 'arch_override_docs' into finalize-training
frostedoyster Jan 20, 2024
2e82d22
Fix docs build?
frostedoyster Jan 19, 2024
3f9c927
Attempt to export
frostedoyster Jan 20, 2024
0142784
Address reviewer comments
frostedoyster Jan 23, 2024
bc60b87
Merge branch 'main' into finalize-training
frostedoyster Jan 23, 2024
6590939
Merge branch 'finalize-training' into export
frostedoyster Jan 23, 2024
236e5a3
Make SOAP-BPNN model saveable
frostedoyster Jan 26, 2024
addd65d
Hack better
frostedoyster Jan 26, 2024
a7811bc
Update `MANIFEST.in`
frostedoyster Jan 26, 2024
f8b2325
Update tests and docs
frostedoyster Jan 26, 2024
ecb8279
Add some comments on the hacks
frostedoyster Jan 26, 2024
27e3bc9
Fix `usage.sh`?
frostedoyster Jan 26, 2024
5fb18c1
Add ASE tutorial
frostedoyster Jan 26, 2024
374b88b
Fix docs?
frostedoyster Jan 26, 2024
3acf607
Fix docs??
frostedoyster Jan 26, 2024
e7397ac
Merge branch 'main' into export
frostedoyster Jan 26, 2024
c34f85c
Fix merge bug
frostedoyster Jan 26, 2024
84a64b5
Try to put a notebook together
frostedoyster Jan 28, 2024
2e004e5
Run correct NVE MD
frostedoyster Jan 28, 2024
199f98a
Also fix units in `metatensor.torch.atomistic`
frostedoyster Jan 31, 2024
b88e586
Turn example into python script
frostedoyster Jan 31, 2024
ed62a5f
Sphinx gallery?
frostedoyster Jan 31, 2024
82f1c22
Sphinx gallery??
frostedoyster Jan 31, 2024
19f77cb
Fix conf.py
frostedoyster Jan 31, 2024
ef9e532
Make README.rst a title
frostedoyster Jan 31, 2024
bf891b4
Title?
frostedoyster Jan 31, 2024
793488b
Added sphinx config
PicoCentauri Jan 31, 2024
54fbe61
Some improvments to the tutorial
PicoCentauri Jan 31, 2024
e7d240b
Try to run gallery as a subprocess of conf.py
frostedoyster Jan 31, 2024
cf069fb
Merge branch 'main' into export
frostedoyster Feb 1, 2024
1623ae1
Retrain model, add symlink
frostedoyster Feb 1, 2024
9dc2a78
Add info about model
PicoCentauri Feb 1, 2024
b02a0eb
Use vanilla sphinx-gallery
PicoCentauri Feb 1, 2024
ecea35f
More details to the tutorial
PicoCentauri Feb 1, 2024
eb54ddf
fix some typos
PicoCentauri Feb 1, 2024
04af489
Merge branch 'export' into ase-tutorial
frostedoyster Feb 1, 2024
12d0c7a
fix wrong title
PicoCentauri Feb 1, 2024
6e5df56
Merge branch 'ase-tutorial' of https://github.com/lab-cosmo/metatenso…
frostedoyster Feb 1, 2024
9fe6305
Fix leftover issue from merge
frostedoyster Feb 2, 2024
4699030
Linter betrayal AGAIN
frostedoyster Feb 2, 2024
cc939da
Run example on the fly
PicoCentauri Feb 2, 2024
629f90d
reorder example files
PicoCentauri Feb 2, 2024
c8e4bb4
finish restructure
PicoCentauri Feb 2, 2024
33214f2
remove output file
PicoCentauri Feb 2, 2024
4a22182
Merge branch 'main' into ase-tutorial
frostedoyster Feb 2, 2024
c22ee68
fix docs
PicoCentauri Feb 2, 2024
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ cython_debug/
# Don't save model outputs
*.pt
!tests/resources/*.pt
!examples/ase/*.pt

# model output directories
outputs/
examples/*.xyz

# sphinx gallery
docs/src/tutorials/gallery
*execution_times*
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ graft src
include LICENSE
include README.md

# TODO: remove once the hack is not needed anymore
include scripts/setup.py

prune docs
prune examples
prune tests
Expand Down
3 changes: 3 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
furo
sphinx >= 7
sphinx-gallery
sphinx-toggleprompt
tomli

ase # for ASE tutorial
1 change: 1 addition & 0 deletions docs/src/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx_toggleprompt",
"sphinx_gallery.load_style",
]

python_use_unqualified_type_names = True
Expand Down
68 changes: 68 additions & 0 deletions docs/src/gallery.py
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if we really need the custom rewrite that we do in metatensor here as well. I think the standard config should be enough for us?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have no clue but I don't have the time to find out

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import os
import shutil
import sys

import sphinx_gallery.gen_gallery


HERE = os.path.realpath(os.path.dirname(__file__))


class AttrDict(dict):
def __init__(self):
super().__init__()
self.__dict__ = self


class PseudoSphinxApp:
"""
Class pretending to be a sphinx App, used to configure and run sphinx-gallery
from the command line, without having an actual sphinx project.
"""

def __init__(self, example):
gallery_dir = os.path.join(
HERE, "tutorials", "gallery", os.path.basename(example)
)
if os.path.exists(gallery_dir):
shutil.rmtree(gallery_dir)

# the options here are the minimal set of options to get sphinx-gallery to run
# feel free to add more if sphinx-gallery uses more options in the future
self.config = AttrDict()
self.config.html_static_path = []
self.config.source_suffix = [".rst"]
self.config.default_role = ""
self.config.sphinx_gallery_conf = {
"filename_pattern": ".*",
"examples_dirs": os.path.join(HERE, "..", "..", example),
"gallery_dirs": gallery_dir,
"min_reported_time": 60,
}

self.builder = AttrDict()
self.builder.srcdir = os.path.join(HERE)
self.builder.outdir = ""
self.builder.name = os.path.basename(example)

self.extensions = []

self.builder.config = AttrDict()
self.builder.config.plot_gallery = "True"
self.builder.config.abort_on_example_error = True
self.builder.config.highlight_language = None

def add_css_file(self, path):
pass


if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"usage: {sys.argv[0]} <example/dir>")
sys.exit(1)

app = PseudoSphinxApp(example=sys.argv[1])

sphinx_gallery.gen_gallery.fill_gallery_conf_defaults(app, app.config)
sphinx_gallery.gen_gallery.update_gallery_conf_builder_inited(app)
sphinx_gallery.gen_gallery.generate_gallery_rst(app)
20 changes: 18 additions & 2 deletions docs/src/getting-started/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,31 @@ the current directory and type
Evaluation
##########

The sub-command to evaluate a already trained model is
The sub-command to evaluate an already trained model is

.. code-block:: bash

metatensor-models eval

.. literalinclude:: ../../../examples/usage.sh
:language: bash
:lines: 9-
:lines: 9-25


Exporting
#########

Exporting a model is very useful if you want to use it in other frameworks,
especially in molecular dynamics simulations.
The sub-command to export an already trained model is

.. code-block:: bash

metatensor-models export

.. literalinclude:: ../../../examples/usage.sh
:language: bash
:lines: 25-

In the next tutorials we show how adjust the dataset section of ``options.yaml`` file
to use it for your own datasets.
1 change: 1 addition & 0 deletions docs/src/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ This is a collection of atomistic models interfaced with ``metatensor``.
:hidden:

getting-started/index
tutorials/index
architectures/index
dev-docs/index
10 changes: 10 additions & 0 deletions docs/src/tutorials/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Tutorials
=========

This sections includes some more advanced tutorials on the usage of the
``metatensor-models`` package.

.. toctree::
:maxdepth: 1

gallery/ase/run_ase
3 changes: 3 additions & 0 deletions examples/ase/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Running molecular dynamics with ASE
===================================

Binary file added examples/ase/exported-model.pt
Binary file not shown.
91 changes: 91 additions & 0 deletions examples/ase/run_ase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""
Running molecular dynamics with ASE
===================================

This tutorial shows how to use an exported model to run an ASE simulation.
"""

# %%
#
# First, we import the necessary libraries:

# NumPy
import numpy as np

# Tools to run the simulation
import ase.md
import ase.md.velocitydistribution
import ase.units

# Integration with ASE calculator for metatensor atomistic models
from metatensor.torch.atomistic.ase_calculator import MetatensorCalculator

# Plotting
import matplotlib.pyplot as plt
import ase.visualize.plot

# The SOAP-BPNN model contains compiled extensions from rascaline.torch
import rascaline.torch


# %%
#
# Next, we initialize the simulation, including importing the model:

# Initial positions (reading them from a file):
atoms = ase.io.read("../../tests/resources/ethanol_reduced_100.xyz")

# Initialize the velocities:
ase.md.velocitydistribution.MaxwellBoltzmannDistribution(atoms, temperature_K=300)

# Load the model and register it as the energy calculator for these ``atoms``:
atoms.calc = MetatensorCalculator("exported-model.pt")

# Define the integrator:
integrator = ase.md.VelocityVerlet(
atoms,
timestep=1.0 * ase.units.fs
)

# Plot the initial configuration:
ase.visualize.plot.plot_atoms(atoms)
plt.show()

# %%
#
# Run a short simulation:

potential_energy = []
kinetic_energy = []
total_energy = []
trajectory = []

for step in range(100):
# run a single simulation step
integrator.run(1)

# collect data about the simulation
potential_energy.append(atoms.get_potential_energy())
kinetic_energy.append(atoms.get_kinetic_energy())
total_energy.append(atoms.get_total_energy())
trajectory.append(atoms.copy())

# Convert to numpy arrays
potential_energy = np.array(potential_energy)
kinetic_energy = np.array(kinetic_energy)
total_energy = np.array(total_energy)

# Plot the final configuration:
ase.visualize.plot.plot_atoms(trajectory[99])
plt.show()

# %%
#
# Plot the evolution of kinetic, potential, and total energy.
# The total energy should approximately be conserved:

plt.plot(range(100), potential_energy-potential_energy.mean(), label="potential energy")
plt.plot(range(100), kinetic_energy-kinetic_energy.mean(), label="kinetic energy")
plt.plot(range(100), total_energy-total_energy.mean(), label="total energy")
plt.legend()
plt.show()
21 changes: 21 additions & 0 deletions examples/ase/train_model/options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defaults:
- architecture: soap_bpnn # architecture used to train the model
- _self_

architecture:
training:
batch_size: 16
num_epochs: 1000
learning_rate: 0.003

# Section defining the parameters for structure and target data
training_set:
structures:
read_from: "../../../tests/resources/ethanol_reduced_100.xyz"
targets:
energy:
key: "energy"
unit: "kcal/mol" # very important to run simulations

validation_set: 0.1
test_set: 0.0
13 changes: 13 additions & 0 deletions examples/usage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,16 @@ head -n 20 output.xyz
# All command line flags of the eval sub-command can be listed via

metatensor-models eval --help

# However, before we export the model, we need to run the following command to
# set up the environment for exporting

python ../scripts/setup.py

# The above script can be found in the `scripts` folder of the repository.

# Finally, the `metatestor-models export`, i.e.,

metatensor-models export model.pt

# creates an `exported-model.pt` file that contains the exported model.
48 changes: 48 additions & 0 deletions scripts/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Since torch.jit.save cannot handle Labels.single(), we need to replace it with
# Labels(names=["_"], values=_dispatch.zeros_like(block.values, (1, 1)))
# in metatensor-operations. This is a hacky way to do it.

import os
import metatensor.operations
import metatensor.torch.atomistic

file = os.path.join(
os.path.dirname(metatensor.operations.__file__),
"reduce_over_samples.py"
)

# Find the line that contains "Labels.single()"
# and replace "Labels.single()" with
# "Labels(names=["_"], values=_dispatch.zeros_like(block.values, (1, 1)))"
with open(file, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if "samples_label = Labels.single()" in line:
lines[i] = line.replace(
"samples_label = Labels.single()",
"samples_label = Labels(names=[\"_\"], values=_dispatch.zeros_like(block.values, (1, 1)))"
)
break

with open(file, "w") as f:
f.writelines(lines)

file = os.path.join(
os.path.dirname(metatensor.torch.atomistic.__file__),
"units.py"
)

# At the moment, unit handling is incorrect in metatensor.torch.atomistic
# This will fix it:
with open(file, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if "return self._conversions[to_unit] / self._conversions[from_unit]" in line:
lines[i] = line.replace(
"return self._conversions[to_unit] / self._conversions[from_unit]",
"return self._conversions[from_unit] / self._conversions[to_unit]"
)
break

with open(file, "w") as f:
f.writelines(lines)
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we hacking metatensor while installing metatensor models?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, the user has to run this, but it's documented (see export PR)

5 changes: 2 additions & 3 deletions src/metatensor/models/cli/eval_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ def eval_model(model: str, structures: str, output: str = "output.xyz") -> None:
loaded_model = load_model(model)
structure_list = read_structures(structures)

# since the second argument is missing,
# this calculates all the available properties:
predictions = loaded_model(structure_list)
# this calculates all the properties that the model is capable of predicting:
predictions = loaded_model(structure_list, loaded_model.capabilities.outputs)

write_predictions(output, predictions, structure_list)
Loading
Loading