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

i-PI integration #307

Merged
merged 28 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bb424fa
Added a stub of an i-PI interface
ceriottm Dec 7, 2020
d1ae923
Update initialization and storing of I-PI interface class
max-veit Dec 11, 2020
0ebe0b1
Partial implementation of i-PI compute function
max-veit Dec 11, 2020
02cf947
Add virial output in the format i-PI expects
max-veit Dec 11, 2020
ebcf075
IT'S ALIIIIIIVE
max-veit Dec 11, 2020
5bc3ffa
Flip virial sign convention to match i-PI's
max-veit Dec 11, 2020
1dd6f41
Add driver script
Lgigli2190 Feb 1, 2021
79e4557
Rename i-PI driver so it's clear what it drives
max-veit Feb 1, 2021
0ef0e8c
Add i-Pi example
Lgigli2190 Feb 11, 2021
1a898e1
Make i-PI calculator into a generic ML-MD interface
max-veit Feb 25, 2021
3a6852a
Remove old, unused i-PI driver scripts
max-veit Feb 25, 2021
cf0e660
Make dependency on tqdm optional
max-veit Feb 25, 2021
68d6cad
Reorganize docs and make a place to discuss i-PI interface
max-veit Mar 22, 2021
c1329c5
Expand doc on MD interfaces
max-veit Mar 22, 2021
547c922
Add simple GAP model (and source data and params) for tests
max-veit Mar 24, 2021
0df18fc
Make generic MD read only the first structure of a given template file
max-veit Mar 24, 2021
7390c79
Add annotations (with basic units) to gap model output file
max-veit Mar 24, 2021
737708f
Add tests for GenericMDCalculator
max-veit Mar 24, 2021
d4479cc
Document extra utilities in krr.py
max-veit Mar 24, 2021
384ae15
Add Zundel i-PI example to online docs
max-veit Mar 25, 2021
d2fd3a9
Update version requirements for compiling docs
max-veit Mar 25, 2021
9027d9e
Rename models/IP*.py to shorter, more Pythonic module names
max-veit Mar 29, 2021
02e2323
Overhaul initialization of generic MD calculator
max-veit Mar 29, 2021
264972a
Remove unneeded serialization of generic MD driver
max-veit Mar 29, 2021
9b529e3
Update KRR utils doc
max-veit Mar 29, 2021
3281e07
Add tests for new GenericMD initialization
max-veit Mar 29, 2021
8a074b3
Update example notebook, remove tqdm dependency from bindings
max-veit Apr 8, 2021
6a9f4bd
Force docutils version to avoid bug in 0.17
max-veit Apr 9, 2021
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
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ The following packages are required for building some optional features:
+==================+=============+====================+
| Documentation | pandoc | (latest) |
+------------------+-------------+--------------------+
| | sphinx | 2.1.2 |
| | sphinx | 2.1.2 or later |
Luthaf marked this conversation as resolved.
Show resolved Hide resolved
+------------------+-------------+--------------------+
| | breathe | 4.13.1 |
| | breathe | 4.14.1 or later |
+------------------+-------------+--------------------+
| | nbsphinx | (latest) |
| | nbsphinx | 0.8.1 or later |
+------------------+-------------+--------------------+

Compiling
Expand Down
2 changes: 1 addition & 1 deletion bindings/rascal/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .krr import train_gap_model, KRR
from .krr import train_gap_model, KRR, compute_KNM
from .kernels import Kernel
130 changes: 130 additions & 0 deletions bindings/rascal/models/genericmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""Generic calculator-style interface for MD"""
import ase.io
import numpy as np

from ..utils import BaseIO, load_obj
from ..neighbourlist.structure_manager import AtomsList, unpack_ase


class GenericMDCalculator:

"""Generic MD driver for a librascal model

Initialize with model JSON and a structure template, and calculate
energies and forces based on position/cell updates _assuming the
order and identity of atoms does not change_.
"""

matrix_indices_in_voigt_notation = (
(0, 0),
(1, 1),
(2, 2),
(1, 2),
(0, 2),
(0, 1),
)

def __init__(
self, model_json, is_periodic, structure_template=None, atomic_numbers=None
):
"""Initialize a model and structure template

Parameters
----------
model_json Filename for a JSON file defining the potential
is_periodic Specify whether the simulation is periodic or not
This helps avoid confusion if a geometry's "periodic"
flags have been set improperly, which can happen e.g.
if ASE cannot read the cell information in a file. If
using a structure template and this is set to True,
will raise an error unless at least one of the PBC
flags in the structure template is on. If set to
False, will raise an error if all PBC flags are not
off. Set to None to skip PBC checking. If not using a
structure template, this setting will determine the PBC
flags of the created atomic structure.
structure_template
Filename for an ASE-compatible Atoms object, used
only to initialize atom types and numbers
atomic_numbers
List of atom types (atomic numbers) to initialize
the atomic structure in case no structure template
is given
"""
super(GenericMDCalculator, self).__init__()
self.model_filename = model_json
self.model = load_obj(model_json)
self.representation = self.model.get_representation_calculator()
self.manager = None
# Structure initialization
self.is_periodic = is_periodic
if structure_template is not None:
self.template_filename = structure_template
self.atoms = ase.io.read(structure_template, 0)
if (is_periodic is not None) and (
is_periodic != np.any(self.atoms.get_pbc())
):
raise ValueError(
"Structure template PBC flags: "
+ str(self.atoms.get_pbc())
+ " incompatible with 'is_periodic' setting"
)
elif atomic_numbers is not None:
self.atoms = ase.Atoms(numbers=atomic_numbers, pbc=is_periodic)
else:
raise ValueError(
"Must specify one of 'structure_template' or 'atomic_numbers'"
)

def calculate(self, positions, cell_matrix):
"""Calculate energies and forces from position/cell update

positions Atomic positions (Nx3 matrix)
cell_matrix Unit cell (in ASE format, cell vectors as rows)
(set to zero for non-periodic simulations)

The units of positions and cell are determined by the model JSON
file; for now, only Å is supported. Energies, forces, and
stresses are returned in the same units (eV and Å supported).
max-veit marked this conversation as resolved.
Show resolved Hide resolved

Returns a tuple of energy, forces, and stress - forces are
returned as an Nx3 array and stresses are returned as a 3x3 array

Stress convention: The stresses have units eV/Å^3
(volume-normalized) and are defined as the gradients of the
energy with respect to the cell parameters.
"""
# Quick consistency checks
if positions.shape != (len(self.atoms), 3):
raise ValueError(
"Improper shape of positions (is the number of atoms consistent?)"
)
if cell_matrix.shape != (3, 3):
raise ValueError("Improper shape of cell info (expected 3x3 matrix)")

# Update ASE Atoms object (we only use ASE to handle any
# re-wrapping of the atoms that needs to take place)
self.atoms.set_cell(cell_matrix)
self.atoms.set_positions(positions)

# Convert from ASE to librascal
if self.manager is None:
#  happens at the begining of the MD run
at = self.atoms.copy()
at.wrap(eps=1e-11)
self.manager = [at]
elif isinstance(self.manager, AtomsList):
structure = unpack_ase(self.atoms, wrap_pos=True)
structure.pop("center_atoms_mask")
self.manager[0].update(**structure)

# Compute representations and evaluate model
self.manager = self.representation.transform(self.manager)
energy = self.model.predict(self.manager)
forces = self.model.predict_forces(self.manager)
stress_voigt = self.model.predict_stress(self.manager)
stress_matrix = np.zeros((3, 3))
stress_matrix[tuple(zip(*self.matrix_indices_in_voigt_notation))] = stress_voigt
# Symmetrize the stress matrix (replicate upper-diagonal entries)
stress_matrix += np.triu(stress_matrix).T
return energy, forces, stress_matrix
20 changes: 11 additions & 9 deletions bindings/rascal/models/kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,7 @@
class Kernel(BaseIO):

"""
Computes the kernel for a given representation. In the following
we refer to the training samples with 'N' and, in the case of
sparse kernels [1], we refer to the pseudo points with 'M'. So a
kernel between the training samples and the pseudo points is
'KNM'. For more information on sparse kernels see
:meth:`rascal.models.krr.train_gap_model`.

Initialize the kernel with the given parameters
Initialize the kernel with the given representation and parameters

Parameters
----------
Expand All @@ -42,9 +35,18 @@ class Kernel(BaseIO):

kernel_type : string
Type of kernel method, either 'Full' (computing exact covariance matrix)
or 'Sparse' (computing GAP [2] like kernel for sparse kernel methods like
or 'Sparse' (computing GAP [2]_ like kernel for sparse kernel methods like
Subset of Regressors)

Notes
-----
In the following
we refer to the training samples with 'N' and, in the case of
sparse kernels [1]_, we refer to the pseudo points with 'M'. So a
kernel between the training samples and the pseudo points is
'KNM'. For more information on sparse kernels see
:meth:`rascal.models.krr.train_gap_model`.

.. [1] Joaquin Quiñonero-Candela, Carl Edward Rasmussen;
A Unifying View of Sparse Approximate Gaussian Process Regression,
6(Dec):1939--1959, 2005.
Expand Down
Loading