{"id":13699066,"url":"https://github.com/openmm/openmm-torch","last_synced_at":"2026-02-23T05:02:01.627Z","repository":{"id":37857847,"uuid":"211377477","full_name":"openmm/openmm-torch","owner":"openmm","description":"OpenMM plugin to define forces with neural networks ","archived":false,"fork":false,"pushed_at":"2025-02-24T20:47:52.000Z","size":237,"stargazers_count":214,"open_issues_count":32,"forks_count":28,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-11-10T06:07:01.355Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openmm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-09-27T18:15:19.000Z","updated_at":"2025-11-01T14:34:56.000Z","dependencies_parsed_at":"2024-08-23T20:47:53.799Z","dependency_job_id":"19d66a38-575c-487c-884c-ce6c66e78a97","html_url":"https://github.com/openmm/openmm-torch","commit_stats":{"total_commits":43,"total_committers":7,"mean_commits":6.142857142857143,"dds":0.6511627906976745,"last_synced_commit":"b76deb4df8661713925a6254613823df8601c9dc"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/openmm/openmm-torch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openmm%2Fopenmm-torch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openmm%2Fopenmm-torch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openmm%2Fopenmm-torch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openmm%2Fopenmm-torch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openmm","download_url":"https://codeload.github.com/openmm/openmm-torch/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openmm%2Fopenmm-torch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29738083,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T04:51:08.365Z","status":"ssl_error","status_checked_at":"2026-02-23T04:49:15.865Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T19:00:57.212Z","updated_at":"2026-02-23T05:02:01.609Z","avatar_url":"https://github.com/openmm.png","language":"C++","funding_links":[],"categories":["Molecular dynamics","Molecular Dynamics"],"sub_categories":["AI4MD Engines-Frameworks"],"readme":"[![GH Actions Status](https://github.com/openmm/openmm-torch/workflows/CI/badge.svg)](https://github.com/openmm/openmm-torch/actions?query=branch%3Amaster+workflow%3ACI)\n[![Conda](https://img.shields.io/conda/v/conda-forge/openmm-torch.svg)](https://anaconda.org/conda-forge/openmm-torch)\n[![Anaconda Cloud Badge](https://anaconda.org/conda-forge/openmm-torch/badges/downloads.svg)](https://anaconda.org/conda-forge/openmm-torch)\n\nOpenMM PyTorch Plugin\n=====================\n\nThis is a plugin for [OpenMM](http://openmm.org) that allows [PyTorch](https://pytorch.org/) static computation graphs\nto be used for defining an OpenMM `TorchForce` object, an [OpenMM `Force` class](http://docs.openmm.org/latest/api-python/library.html#forces) that computes a contribution to the potential energy or used as a collective variable via [`CustomCVForce`](http://docs.openmm.org/latest/api-python/generated/simtk.openmm.openmm.CustomCVForce.html#simtk.openmm.openmm.CustomCVForce).  \n\nTo use it, you create a PyTorch model that takes a `(nparticles,3)` tensor of particle positions (in nanometers) as input and produces energy (in kJ/mol) or the value of the collective variable as output.  \nThe `TorchForce` provided by this plugin can then use the model to compute energy contributions or apply forces to particles during a simulation.\n`TorchForce` also supports the use of global context parameters that can be fed to the model and changed dynamically during runtime.\n\nInstallation\n============\n\nInstalling with conda\n---------------------\n\nWe provide [conda](https://docs.conda.io/) packages for Linux and MacOS via [`conda-forge`](https://conda-forge.org/), which can be installed from the [conda-forge channel](https://anaconda.org/conda-forge/openmm-torch):\n```bash\nconda install -c conda-forge openmm-torch\n```\nIf you don't have `conda` available, we recommend installing [Miniconda for Python 3](https://docs.conda.io/en/latest/miniconda.html) to provide the `conda` package manager.  \n\nBuilding from source\n--------------------\n\nThis plugin uses [CMake](https://cmake.org/) as its build system.  \nBefore compiling you must install [LibTorch](https://pytorch.org/cppdocs/installing.html), which is the PyTorch C++ API, by following the instructions at https://pytorch.org.\nYou can then follow these steps:\n\n1. Create a directory in which to build the plugin.\n\n2. Run the CMake GUI or `ccmake`, specifying your new directory as the build directory and the top\nlevel directory of this project as the source directory.\n\n3. Press \"Configure\".  (Do not worry if it produces an error message about not being able to find PyTorch.)\n\n4. Set `OPENMM_DIR` to point to the directory where OpenMM is installed.  This is needed to locate\nthe OpenMM header files and libraries.  If you are unsure of what directory this is, the following\nscript will print it out.\n\n```python\nfrom simtk import openmm\nimport os\nprint(os.path.dirname(openmm.version.openmm_library_path))\n```\n\n5. Set `PYTORCH_DIR` to point to the directory where you installed the LibTorch.\n\n6. Set `CMAKE_INSTALL_PREFIX` to the directory where the plugin should be installed.  Usually,\nthis will be the same as `OPENMM_DIR`, so the plugin will be added to your OpenMM installation.\n\n7. If you plan to build the OpenCL platform, make sure that `OPENCL_INCLUDE_DIR` and\n`OPENCL_LIBRARY` are set correctly, and that `NN_BUILD_OPENCL_LIB` is selected.\n\n8. If you plan to build the CUDA platform, make sure that `CUDA_TOOLKIT_ROOT_DIR` is set correctly\nand that `NN_BUILD_CUDA_LIB` is selected.\n\n9. Press \"Configure\" again if necessary, then press \"Generate\".\n\n10. Use the build system you selected to build and install the plugin.  For example, if you\nselected Unix Makefiles, type `make install` to install the plugin, and `make PythonInstall` to\ninstall the Python wrapper.\n\nUsing the OpenMM PyTorch plugin\n===============================\n\nTutorials\n---------\n\n- [A simple simulation of alanine dipeptide with ANI-2x using OpenMM-Torch and NNPOps](tutorials/openmm-torch-nnpops.ipynb)\n\nExporting a PyTorch model for use in OpenMM\n-------------------------------------------\n\nThe first step is to create a PyTorch model defining the calculation to perform.  \nIt should take particle positions in nanometers (in the form of a `torch.Tensor` of shape `(nparticles,3)` as input,\nand return the potential energy in kJ/mol as a `torch.Scalar` as output.  \n\nThe model must then be converted to a [TorchScript](https://pytorch.org/docs/stable/jit.html) module and saved to a file.  \nConverting to TorchScript can usually be done with a single call to [`torch.jit.script()`](https://pytorch.org/docs/stable/generated/torch.jit.script.html#torch.jit.script) or [`torch.jit.trace()`](https://pytorch.org/docs/stable/generated/torch.jit.trace.html#torch.jit.trace),\nalthough more complicated models can sometimes require extra steps.  \nSee the [PyTorch documentation](https://pytorch.org/tutorials/beginner/Intro_to_TorchScript_tutorial.html) for details.  \n\nHere is a simple Python example that does this for a very simple potential---a harmonic force attracting every particle to the origin:\n\n```python\nimport torch\n\nclass ForceModule(torch.nn.Module):\n    \"\"\"A central harmonic potential as a static compute graph\"\"\"\n    def forward(self, positions):\n        \"\"\"The forward method returns the energy computed from positions.\n\n        Parameters\n        ----------\n        positions : torch.Tensor with shape (nparticles,3)\n           positions[i,k] is the position (in nanometers) of spatial dimension k of particle i\n\n        Returns\n        -------\n        potential : torch.Scalar\n           The potential energy (in kJ/mol)\n        \"\"\"\n        return torch.sum(positions**2)\n\n# Render the compute graph to a TorchScript module\nmodule = torch.jit.script(ForceModule())\n\n# Serialize the compute graph to a file\nmodule.save('model.pt')\n```\n\nTo use the exported model in a simulation, create a `TorchForce` object and add it to your `System`.  \nThe constructor takes the path to the saved model as an argument.  \nAlternatively, the scripted module can be provided directly.  \nFor example,\n```python\n# Create the TorchForce from the serialized compute graph\nfrom openmmtorch import TorchForce\n# Construct using a serialized module:\ntorch_force = TorchForce('model.pt')\n# or using an instance of the module:\ntorch_force = TorchForce(module)\n\n# Add the TorchForce to your System\nsystem.addForce(torch_force)\n```\n\nDefining a model that uses periodic boundary conditions\n-------------------------------------------------------\n\nWhen defining the model to perform a calculation, you may want to apply periodic boundary conditions.  \n\nTo do this, call `setUsesPeriodicBoundaryConditions(True)` on the `TorchForce`.  \nThe graph is then expected to take a second input, which contains the current periodic box vectors.  \nYou can make use of them in whatever way you want for computing the force.  \nFor example, the following code applies periodic boundary conditions to each\nparticle position to translate all of them into a single periodic cell:\n\n```python\nclass ForceModule(torch.nn.Module):\n    \"\"\"A central harmonic force with periodic boundary conditions\"\"\"\n    def forward(self, positions, boxvectors):\n        \"\"\"The forward method returns the energy computed from positions.\n\n        Parameters\n        ----------\n        positions : torch.Tensor with shape (nparticles,3)\n           positions[i,k] is the position (in nanometers) of spatial dimension k of particle i\n        boxvectors : torch.tensor with shape (3,3)\n           boxvectors[i,k] is the box vector component k (in nanometers) of box vector i\n\n        Returns\n        -------\n        potential : torch.Scalar\n           The potential energy (in kJ/mol)\n        \"\"\"\n        # Image articles in rectilinear box\n        # NOTE: This will not work for non-orthogonal boxes\n        boxsize = boxvectors.diag()\n        periodicPositions = positions - torch.floor(positions/boxsize)*boxsize\n        # Compute central harmonic potential\n        return torch.sum(periodicPositions**2)\n```\n\nNote that this code assumes a rectangular box.  Applying periodic boundary\nconditions with a triclinic box requires a slightly more complicated calculation.\n\nDefining global parameters that can be modified within the Context\n------------------------------------------------------------------\n\nThe graph can also take arbitrary scalar arguments that are passed in at\nruntime.  For example, this model multiplies the energy by `scale`, which is\npassed as an argument to `forward()`.\n\n```python\nclass ForceModule(torch.nn.Module):\n    \"\"\"A central harmonic force with a user-defined global scale parameter\"\"\"\n    def forward(self, positions, scale):\n        \"\"\"The forward method returns the energy computed from positions.\n\n        Parameters\n        ----------\n        positions : torch.Tensor with shape (nparticles,3)\n           positions[i,k] is the position (in nanometers) of spatial dimension k of particle i\n        scale : torch.Scalar\n           A scalar tensor defined by 'TorchForce.addGlobalParameter'.\n           Here, it scales the contribution to the potential.\n           Note that parameters are passed in the order defined by `TorchForce.addGlobalParameter`, not by name.\n\n        Returns\n        -------\n        potential : torch.Scalar\n           The potential energy (in kJ/mol)\n        \"\"\"\n        return scale*torch.sum(positions**2)\n```\n\nWhen you create the `TorchForce`, call `addGlobalParameter()` once for each extra argument.\n\n```python\ntorch_force.addGlobalParameter('scale', 2.0)\n```\n\nThis specifies the name of the parameter and its initial value.  The name\ndoes not need to match the argument to `forward()`.  All global parameters\nare simply passed to the model in the order you define them.  The advantage\nof using global parameters is that you can change their values at any time\nby calling `setParameter()` on the `Context`.\n\n```python\ncontext.setParameter('scale', 5.0)\n```\n\nComputing forces in the model\n-----------------------------\n\nIn the examples above, the PyTorch model computes the potential energy.  Backpropagation\ncan be used to compute the corresponding forces.  That always works, but sometimes you\nmay have a more efficient way to compute the forces than the generic backpropagation\nalgorithm.  In that case, you can have the model directly compute forces as well as\nenergy, returning both of them in a tuple.  Remember that the force is the *negative*\ngradient of the energy.\n\n```python\nimport torch\n\nclass ForceModule(torch.nn.Module):\n    \"\"\"A central harmonic potential that computes both energy and forces.\"\"\"\n    def forward(self, positions):\n        \"\"\"The forward method returns the energy and forces computed from positions.\n\n        Parameters\n        ----------\n        positions : torch.Tensor with shape (nparticles,3)\n           positions[i,k] is the position (in nanometers) of spatial dimension k of particle i\n\n        Returns\n        -------\n        potential : torch.Scalar\n           The potential energy (in kJ/mol)\n        forces : torch.Tensor with shape (nparticles,3)\n           The force (in kJ/mol/nm) on each particle\n        \"\"\"\n        return (torch.sum(positions**2), -2*positions)\n```\n\nWhen you create the `TorchForce`, call `setOutputsForces()` to tell it to expect the model\nto return forces.\n\n```python\ntorch_force.setOutputsForces(True)\n```\n\nComputing energy derivatives with respect to global parameters\n--------------------------------------------------------------\n\nTorchForce can compute derivatives of the energy with respect to global parameters.. In order to do so the global parameters must be registered as energy derivatives. This is done by calling `addEnergyParameterDerivative()` for each parameter.\n\nThe parameter derivatives can be queried by calling `getEnergyParameterDerivatives()` on the `State` object returned by `Context.getState()`. The result is a dictionary with the parameter names as keys and the derivatives as values.\n\n```python\nimport torch as pt\nfrom openmmtorch import TorchForce\nimport openmm as mm\n\n\nclass ForceWithParameters(pt.nn.Module):\n\n    def __init__(self):\n        super(ForceWithParameters, self).__init__()\n\n    def forward(self, positions: pt.Tensor, k: pt.Tensor) -\u003e pt.Tensor:\n        return k * pt.sum(positions**2)\n\n\nnumParticles = 10\nsystem = mm.System()\nfor _ in range(numParticles):\n    system.addParticle(1.0)\n\nmodel = pt.jit.script(ForceWithParameters())\ntforce = TorchForce(model)\ntforce.setOutputsForces(False)\ntforce.addGlobalParameter(\"k\", 2.0)\ntforce.addEnergyParameterDerivative(\"k\")\nsystem.addForce(tforce)\ncontext = mm.Context(system, mm.VerletIntegrator(1.0))\ncontext.setPositions(pt.rand(numParticles, 3).numpy())\nstate = context.getState(getParameterDerivatives=True)\ndEdk = state.getEnergyParameterDerivatives()[\"k\"]\n```\n\n\n\nRecording the model into a CUDA graph\n-------------------------------------\n\nYou can ask `TorchForce` to run the model using [CUDA graphs](https://pytorch.org/docs/stable/notes/cuda.html#cuda-graphs). Not every model will be compatible with this feature, but it can be a significant performance boost for some models. To enable it the CUDA platform must be used and an special property must be provided to `TorchForce`:\n\n```python\ntorch_force.setProperty(\"useCUDAGraphs\", \"true\")\n# The property can also be set at construction\ntorch_force = TorchForce('model.pt', {'useCUDAGraphs': 'true'})\n```\n\nThe first time the model is run, it will be compiled (also known as recording) into a CUDA graph. Subsequent runs will use the compiled graph, which can be significantly faster. It is possible that compilation fails, in which case an `OpenMMException` will be raised. If that happens, you can disable CUDA graphs and try again.\n\nIt is required to run the model at least once before recording, in what is known as warmup.\nBy default ```TorchForce``` will run the model just a few times before recording, but controlling warmup steps might be desired. In these cases one can set the property ```CUDAGraphWarmupSteps```:\n```python\ntorch_force.setProperty(\"CUDAGraphWarmupSteps\", \"12\")\n```\n\nList of available properties\n----------------------------\n\nSome ```TorchForce``` functionalities can be customized by setting properties on an instance of it. Properties can be set at construction or by using ```setProperty```. A property is a pair of key/value strings. For instance:\n\n```python\ntorch_force = TorchForce('model.pt', {'useCUDAGraphs': 'true'})\n#Alternatively setProperty can be used to configure an already created instance.\n#torch_force.setProperty(\"useCUDAGraphs\", \"true\")\nprint(\"Current properties:\")\nfor property in torch_force.getProperties():\n    print(property.key, property.value)\n```\n\nCurrently, the following properties are available:\n\n1. useCUDAGraphs: Turns on the CUDA graph functionality\n2. CUDAGraphWarmupSteps: When CUDA graphs are being used, controls the number of warmup calls to the model before recording.\n\nLicense\n=======\n\nThis is part of the OpenMM molecular simulation toolkit originating from\nSimbios, the NIH National Center for Physics-Based Simulation of\nBiological Structures at Stanford, funded under the NIH Roadmap for\nMedical Research, grant U54 GM072970. See https://simtk.org.\n\nPortions copyright (c) 2018-2020 Stanford University and the Authors.\n\nAuthors: Peter Eastman\n\nContributors: Raimondas Galvelis, Jaime Rodriguez-Guerra, Yaoyi Chen, John D. Chodera\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nTHE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenmm%2Fopenmm-torch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenmm%2Fopenmm-torch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenmm%2Fopenmm-torch/lists"}