energy_force.py 2.76 KB
Newer Older
Gao, Xiang's avatar
Gao, Xiang committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding: utf-8 -*-
"""
Computing Energy and Force Using Builtin Models
===============================================

TorchANI has a model ensemble trained by NeuroChem on the `ANI-1x dataset`_.
These models are shipped with TorchANI and can be used directly.

.. _ANI-1x dataset:
  https://aip.scitation.org/doi/abs/10.1063/1.5023802
"""

###############################################################################
# To begin with, let's first import the modules we will use:
Xiang Gao's avatar
Xiang Gao committed
15
16
17
import torch
import torchani

Gao, Xiang's avatar
Gao, Xiang committed
18
19
###############################################################################
# Let's now manually specify the device we want TorchANI to run:
Xiang Gao's avatar
Xiang Gao committed
20
21
device = torch.device('cpu')

Gao, Xiang's avatar
Gao, Xiang committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
###############################################################################
# Let's now load the built-in models and create a pipeline of AEV computer,
# neural networks, and energy shifter. This pipeline will first compute AEV,
# then use all models in the ensemble to compute molecular energies, and take
# the average of these energies to obtain a final output. The reason we need an
# energy shifter in the end is that the output of these networks is not the
# total energy but the total energy subtracted by a self energy for each atom.
builtin = torchani.neurochem.Builtins()
model = torch.nn.Sequential(
  builtin.aev_computer,
  builtin.models,
  builtin.energy_shifter
)

###############################################################################
# Now let's define the coordinate and species. If you just want to compute the
# energy and force for a single structure like in this example, you need to
# make the coordinate tensor has shape ``(1, Na, 3)`` and species has shape
# ``(1, Na)``, where ``Na`` is the number of atoms in the molecule, the
# preceding ``1`` in the shape is here to support batch processing like in
# training. If you have ``N`` different structures to compute, then make it
# ``N``.
Xiang Gao's avatar
Xiang Gao committed
44
45
46
47
48
coordinates = torch.tensor([[[0.03192167,  0.00638559,  0.01301679],
                             [-0.83140486,  0.39370209, -0.26395324],
                             [-0.66518241, -0.84461308,  0.20759389],
                             [0.45554739,   0.54289633,  0.81170881],
                             [0.66091919,  -0.16799635, -0.91037834]]],
Gao, Xiang's avatar
Gao, Xiang committed
49
50
                           requires_grad=True, device=device)
species = builtin.consts.species_to_tensor('CHHHH').to(device).unsqueeze(0)
Xiang Gao's avatar
Xiang Gao committed
51

Gao, Xiang's avatar
Gao, Xiang committed
52
53
###############################################################################
# Now let's compute energy and force:
54
_, energy = model((species, coordinates))
Gao, Xiang's avatar
Gao, Xiang committed
55
derivative = torch.autograd.grad(energy.sum(), coordinates)[0]
Xiang Gao's avatar
Xiang Gao committed
56
57
force = -derivative

Gao, Xiang's avatar
Gao, Xiang committed
58
59
###############################################################################
# And print to see the result:
Xiang Gao's avatar
Xiang Gao committed
60
print('Energy:', energy.item())
Gao, Xiang's avatar
Gao, Xiang committed
61
print('Force:', force.squeeze())