Using the ASE calculators

This tutorial demonstrates how to use the ASE calculators for neuroevolution potentials (NEP), which allow one to calculate energies, forces and stresses for an atomic configuration, specified in the form of an Atoms object. This enables one to programmatically calculate properties that would otherwise require writing a large number of GPUMD input files and potentially tedious extraction of the results.

calorine provides two different ASE calculators for NEP calculations, one that uses the GPU implementation and one that uses the CPU implementation of NEP. For smaller calculations the CPU calculators is usually more performant. For very large simulations and for comparison the GPU calculator can be useful as well.

CPU-based calculator

Basic usage

First we define an atomic structure in the form of an Atoms object. Next we create a calculator instance by specifying the path to a NEP model file in nep.txt format. In this tutorial, we use a NEP3 model for PbTe. Finally, we attach the calculator to the Atoms object.

from import read
from import bulk
from calorine.calculators import CPUNEP

structure = bulk('PbTe', crystalstructure='rocksalt', a=6.7)
calc = CPUNEP('PbTe_NEP3.txt')
structure.calc = calc

Now, we can readily calculate energies, forces and stresses.

print('Energy (eV):', structure.get_potential_energy())
print('Forces (eV/Å):\n', structure.get_forces())
print('Stress (GPa):\n', structure.get_stress())
Energy (eV): -7.681070759348718
Forces (eV/Å):
 [[ 2.70616862e-16  2.85239922e-17 -1.16068684e-16]
 [-2.70616862e-16 -2.85239922e-17  1.16068684e-16]]
Stress (GPa):
 [ 4.82127071e-03  4.82127071e-03  4.82127071e-03  8.44618290e-19
 -2.15829022e-18  9.93950137e-18]

Calculate energy-volume curve

To demonstrate the capabilities of the ASE calculator, we will now calculate an energy-volume curve with the PbTe potential.

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

energies = []
volumes = []

structure_copy = structure.copy()
original_cell = structure.cell.copy()

structure_copy.calc = calc

for scale in np.arange(0.9, 1.11, 0.01):
    structure_copy.set_cell(scale * original_cell, scale_atoms=True)
    energies.append(structure_copy.get_potential_energy() / len(structure_copy))

fig, ax = plt.subplots()
ax.plot(volumes, energies, '-o')
ax.set_xlabel('Volume (Å^3)')
ax.set_ylabel('Energy (eV/atom)');

Calculate dipole moments

The calculator also supports the calculation of dipole moments. Note that you must have a NEP model trained to predict dipoles; otherwise the output will be nonsensical. Refer to the GPUMD documentation for information on how to train a dipole model.

dipole_model = 'nep4_dipole.txt'
structure = read('')
calc = CPUNEP(dipole_model)
structure.calc = calc

dipole = structure.get_dipole_moment()
dft_dipole =['dipole']

print('DFT dipole moment:'.ljust(30) +  f'{dft_dipole} a.u.')
print(f'NEP predicted dipole moment:'.ljust(30) + f'{dipole} a.u.')
DFT dipole moment:            [4.85503 0.07166 0.16004] a.u.
NEP predicted dipole moment:  [4.78034782 0.03274603 0.04843106] a.u.

GPU-based calculator

The basic usage of the GPUNEP calculator class is completely analoguous to the CPUNEP calculator. We create an atomic structure and attach the calculator object.

from calorine.calculators import GPUNEP

structure = bulk('PbTe', crystalstructure='rocksalt', a=6.7)
calc = GPUNEP('PbTe_NEP3.txt')
structure.calc = calc

Afterwards we can readily obtain energies, forces, and stresses.

print('Energy (eV):', structure.get_potential_energy())
print('Forces (eV/Å):\n', structure.get_forces())
print('Stresses (eV/Å^3):\n', structure.get_stress())
Energy (eV): -7.6810722351
Forces (eV/Å):
 [[ 3.25407e-08  3.83373e-08 -4.52696e-08]
 [-3.25407e-08 -3.83373e-08  4.52696e-08]]
Stresses (eV/Å^3):
 [ 4.82122450e-03  4.82122450e-03  4.82122782e-03 -3.37569291e-10
 -3.37569293e-10 -9.22673676e-10]

Temporary and specified directories

Under the hood, the GPUNEP calculator creates a directory and writes the input files necessary to run GPUMD. By default, this is done in temporary directories that are automatically removed once the calculations has finished. It is also possible to run in a user-specified directory that will be kept after the calculations finish. This is especially useful when running molecular dynamics simulations (see below).


After this is run, there should be a new directory, my_directory, in which input and output files from GPUMD are available. This can be useful for debugging.

Running custom molecular dynamics simulations

To take advantage of the Python workflow as well as raw speed of the GPU accelerated NEP implementation, the GPUNEP calculator contains a convenience function for running customized molecular dynamics simulations. This should typically be done in a specified directory. The parameters of the file are specified as a list of tuples with two elements, the first being the keyword name and the second any arguments to that keyword.

supercell = structure.repeat(5)
structure.calc = calc
parameters = [('velocity', 300),
              ('dump_thermo', 100),
              ('dump_position', 100),
              ('ensemble', ('nvt_lan', 300, 300, 100)),
              ('run', 1000)]

Once this is run, the results are available in the folder my_md_simulations.