Skip to content

Commit

Permalink
Add pre commit (duartegroup#66)
Browse files Browse the repository at this point in the history
Added pre-commit hooks and Ruff linter to check the files before committing. This PR also includes changes suggested by Ruff, fixed either automatically or manually. Ruff formatter will be added in the follow-up PR. 

* Add pre-commit configuration
* Automatic and manual fix of errors found by linter
* Add pre-commit to dependencies
* Update README.md
  • Loading branch information
juraskov authored Oct 30, 2023
1 parent be29fa9 commit 41fbb2c
Show file tree
Hide file tree
Showing 38 changed files with 142 additions and 71 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "Lint"

on:
push:
pull_request:

jobs:
pre-commit:
env:
SKIP: 'no-commit-to-branch'
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Run pre-commit
uses: pre-commit/action@v3.0.0
21 changes: 21 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
default_language_version:
# all hooks should run with python 3.6+
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: no-commit-to-branch
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
- id: check-added-large-files
args: ['--maxkb=500', '--enforce-all']
exclude: mlptrain/sampling/tests/data.zip
- id: check-yaml

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.1.3
hooks:
- id: ruff
args: [--show-source, --fix]
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[![Test with pytest](https://github.com/duartegroup/mlp-train/actions/workflows/pytest.yml/badge.svg?event=push)](https://github.com/duartegroup/mlp-train/actions/workflows/pytest.yml)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![License](https://img.shields.io/badge/License-MIT%202.0-blue.svg)](https://opensource.org/licenses/mit)
[![GitHub issues](https://img.shields.io/github/issues/duartegroup/mlp-train.svg)](https://github.com/duartegroup/mlp-train/issues)

# mlp-train
General machine learning potentials (MLP) training for molecular systems in gas phase and solution
Expand All @@ -11,8 +13,7 @@ Available models:
- MACE


***
### Install
## Install

Each model is installed into individual conda environment:

Expand All @@ -27,12 +28,21 @@ Each model is installed into individual conda environment:
./install_mace.sh
```


### Notes

- Units are: distance (Å), energy (eV), force (eV Å$`^{-1}`$), time (fs)

## Citation
## For developers

We are happy to accept pull requests from users. Please first fork mlp-train repository. We use `pre-commit`, `Ruff` and `pytest` to check the code. Your PR needs to pass through these checks before is accepted. `Pre-commit` is installed as one the dependecies. To use it in your repository, run the following command in the mlp-train folder:

```
pre-commit install
```

`Pre-commit` will then run automatically at each commit and will take care of installation and running of `Ruff`.

## Citations

If _mlptrain_ is used in a publication please consider citing the [paper](https://doi.org/10.1039/D2CP02978B):

Expand All @@ -47,3 +57,8 @@ If _mlptrain_ is used in a publication please consider citing the [paper](https:
journal = {Phys. Chem. Chem. Phys.}
}
```

## Contact

For bugs or implementation requests, please use [GitHub Issues](https://github.com/duartegroup/mlp-train/issues)

1 change: 0 additions & 1 deletion create_conda_environment.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/bin/bash
# NOTE: This script should not be called on its own,
# but should be sourced from other install scripts such as install_ace.sh
set -euo pipefail
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ channels:
dependencies:
- python=3.9
- pip
- pre-commit
- ase
- autode=1.1
- coloredlogs
Expand Down
1 change: 1 addition & 0 deletions environment_ace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ channels:
dependencies:
- python=3.9
- pip
- pre-commit
- ase
- autode=1.1
- coloredlogs
Expand Down
1 change: 1 addition & 0 deletions environment_mace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ channels:
dependencies:
- python=3.9
- pip
- pre-commit
- ase
- autode=1.1
- coloredlogs
Expand Down
1 change: 0 additions & 1 deletion examples/DA_paper/1d_fes/fes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import sys
import mlptrain as mlt
import numpy as np
from mlptrain.box import Box
Expand Down
5 changes: 1 addition & 4 deletions examples/DA_paper/2D_pes/pes.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,6 @@ def get_energy(self, calc):
def get_free_energy(self, calc):
return None

def get_free_energy(self, calc):
return None

def get_enthalpy(self, calc):
return None

Expand Down Expand Up @@ -263,7 +260,7 @@ def optimise_with_fix_solute(solute, configuration, fmax, mlp, constraint = True
from ase.optimize import BFGS
from ase.io.trajectory import Trajectory as ASETrajectory

assert configuration.box != None, 'configuration must have box'
assert configuration.box is not None, 'configuration must have box'
logger.info('Optimise the configuration with fixed solute (solute coords should at the first in configuration coords) by MLP')

n_cores = kwargs['n_cores'] if 'n_cores' in kwargs else min(Config.n_cores, 8)
Expand Down
16 changes: 7 additions & 9 deletions examples/DA_paper/training/explicit/endo_ace_ex.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import mlptrain as mlt
import numpy as np
from autode.atoms import Atoms, Atom
from autode.atoms import Atom
from mlptrain.log import logger
from mlptrain.box import Box
from mlptrain.training.selection import MaxAtomicEnvDistance
import random

mlt.Config.n_cores = 10
mlt.Config.orca_keywords = ['wB97M-D3BJ', 'def2-TZVP','def2/J', 'RIJCOSX','EnGrad']
Expand All @@ -30,7 +29,6 @@ def add_water(solute, n = 2):
n: number of water molecules to add"""
from ase import Atoms
from ase.calculators.tip3p import rOH, angleHOH
from ase.io import read , write

# water molecule
x = angleHOH * np.pi / 180 / 2
Expand All @@ -46,7 +44,7 @@ def add_water(solute, n = 2):
water0.rotate(180, 'x')
water0.rotate(180, 'z')

assert solute.box != None, 'configuration must have box'
assert solute.box is not None, 'configuration must have box'
sol = solute.ase_atoms
sol.center()
sys = sol.copy()
Expand Down Expand Up @@ -104,13 +102,13 @@ def solvation(solute_config, solvent_config, apm, radius, enforce = True):
"""function to generate solvated system by adding the solute at the center of box,
then remove the overlapped solvent molecules
adapted from https://doi.org/10.1002/qua.26343
solute: mlt.Configuration() solute.box != None
solvent: mlt.Configuration() solvent.box != None
solute: mlt.Configuration() solute.box is not None
solvent: mlt.Configuration() solvent.box is not None
aps: number of atoms per solvent molecule
radius: cutout radius around each solute atom
enforce: True / False Wrap solvent regardless of previous solvent PBC choices"""
assert solute_config.box != None, 'configuration must have box'
assert solvent_config.box != None, 'configuration must have box'
assert solute_config.box is not None, 'configuration must have box'
assert solvent_config.box is not None, 'configuration must have box'

solute = solute_config.ase_atoms
solvent = solvent_config.ase_atoms
Expand Down Expand Up @@ -221,7 +219,7 @@ def generate_init_configs(n, bulk_water = True, TS = True):

# TS bounded with two water molecules at carbonyl group to form hydrogen bond
else:
assert TS == True, 'cannot generate initial configuration'
assert TS is True, 'cannot generate initial configuration'
for i in range(n):
TS_with_water = add_water(solute=TS, n=2)
init_configs.append(TS_with_water)
Expand Down
20 changes: 13 additions & 7 deletions examples/DA_paper/uphill/generate_rs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from mlptrain.log import logger
from mlptrain.config import Config
from mlptrain.md import _convert_ase_traj
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
from numpy.random import RandomState
import numpy as np

mlt.Config.n_cores = 10
Expand All @@ -28,13 +30,13 @@ def from_ase_to_autode(atoms):

def solvation(solute_config, solvent_config, apm, radius, enforce = True):
"""same function applied in training an MLP for reaction in explicit water
solute: mlt.Configuration() solute.box != None
solvent: mlt.Configuration() solvent.box != None
solute: mlt.Configuration() solute.box is not None
solvent: mlt.Configuration() solvent.box is not None
aps: number of atoms per solvent molecule
radius: cutout radius around each solute atom
enforce: True / False Wrap solvent regardless of previous solvent PBC choices"""
assert solute_config.box != None, 'configuration must have box'
assert solvent_config.box != None, 'configuration must have box'
assert solute_config.box is not None, 'configuration must have box'
assert solvent_config.box is not None, 'configuration must have box'

solute = solute_config.ase_atoms
solvent = solvent_config.ase_atoms
Expand Down Expand Up @@ -135,7 +137,7 @@ def mlpmd_fix_solute(solute, configuration, mlp, temp, dt, interval, n_steps, **
from ase.io.trajectory import Trajectory as ASETrajectory
from ase.md.langevin import Langevin
from ase import units as ase_units
assert configuration.box != None, 'configuration must have box'
assert configuration.box is not None, 'configuration must have box'

logger.info('Run MLP MD with fixed solute (solute coords should at the first in configuration coords) by MLP')

Expand Down Expand Up @@ -174,7 +176,7 @@ def optimize_sys(configuration, mlp, **kwargs):
# applied MLP to optimised geometry with BFGS method
from ase.io.trajectory import Trajectory as ASETrajectory
from ase.optimize import BFGS
assert configuration.box != None, 'configuration must have box'
assert configuration.box is not None, 'configuration must have box'

logger.info('Optimise the configuratoin with fixed solute (solute coords should at the first in configuration coords) by MLP')

Expand Down Expand Up @@ -266,6 +268,10 @@ def baised_md(configuration, mlp, temp, dt, interval, bias, **kwargs):
rng=RandomState())

traj = ASETrajectory("tmp.traj", 'w', ase_atoms)
energies = []

def append_energy(_atoms=ase_atoms):
energies.append(_atoms.get_potential_energy())

if temp > 0: # Default Langevin NVT
dyn = Langevin(ase_atoms, dt * ase_units.fs,
Expand Down Expand Up @@ -312,7 +318,7 @@ def generate_rs(TS, solution, mlp, box_size):
for i, species in enumerate(reactants):
bias = mlt.Bias(zeta_func=mlt.AverageDistance((1,12), (6,11)), kappa=0.5, reference=ref[i])
traj = baised_md(configuration=species,
mlp=endo,
mlp=mlp,
temp=300,
dt=0.5,
interval=20,
Expand Down
21 changes: 3 additions & 18 deletions examples/DA_paper/uphill/uphill.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import mlptrain as mlt
import numpy as np
import matplotlib.pyplot as plt
from mlptrain.log import logger
import random
from mlptrain.box import Box
from scipy.spatial import distance_matrix
import os
import math
from ase.constraints import Hookean
from ase.geometry import find_mic
from generate_rs import generate_rs

mlt.Config.n_cores = 10
Expand Down Expand Up @@ -116,7 +111,7 @@ def get_cavity_volume(atoms = ase_atoms):

dyn.attach(append_energy, interval=interval)
dyn.attach(get_reaction_coord,interval=interval)
dyn.attach(get_cavity_volumn,interval=interval)
dyn.attach(get_cavity_volume,interval=interval)
dyn.attach(traj.write, interval=interval)

logger.info(f'Running {n_steps:.0f} steps with a timestep of {dt} fs')
Expand All @@ -133,20 +128,10 @@ def get_cavity_volume(atoms = ase_atoms):


def traj_study(configs, ml_potential, init_md_time_fs = 500, max_time_fs = 3000):
num_config = len(configs)

C2_C7_recrossing_list = []
C4_C6_recrossing_list = []

C2_C7_product_list = []
C4_C6_product_list = []


C2_C7_initial_list = []
C4_C6_initial_list = []

time_sep = []
intermediate_time = []

for k in range(500):
config =configs[k]
logger.info(f'start trajectory study for {k} th configuration')
Expand Down Expand Up @@ -175,7 +160,7 @@ def traj_study(configs, ml_potential, init_md_time_fs = 500, max_time_fs = 300
temp=300,
dt=0.5,
interval=2,
fs=md_time_f)
fs=md_time_fs_f)
ending = 0
for (i, j) in zip (C2_C7_list, C4_C6_list):
logger.info(f'C2-C7 and C4-C6 bond lengths are {(i,j)}')
Expand Down
1 change: 1 addition & 0 deletions mlptrain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'Box',
'Bias',
'PlumedBias',
'PlumedCalculator',
'UmbrellaSampling',
'Metadynamics',
'AverageDistance',
Expand Down
2 changes: 1 addition & 1 deletion mlptrain/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from autode.wrappers.keywords import *
from autode.wrappers.keywords import GradientKeywords


class _ConfigClass:
Expand Down
2 changes: 2 additions & 0 deletions mlptrain/configurations/calculate.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import mlptrain
import autode
from typing import Tuple
from mlptrain.log import logger
from mlptrain.utils import work_in_tmp_dir
Expand Down
11 changes: 7 additions & 4 deletions mlptrain/configurations/configuration.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import mlptrain
import ase
import numpy as np
from typing import Optional, Union, List
from copy import deepcopy
from autode.atoms import AtomCollection, Atoms, Atom
from ase.atoms import Atoms
from autode.atoms import AtomCollection, Atom
import autode.atoms
import ase.atoms
from mlptrain.log import logger
from mlptrain.energy import Energy
from mlptrain.forces import Forces
Expand All @@ -14,7 +17,7 @@ class Configuration(AtomCollection):
"""Configuration of atoms"""

def __init__(self,
atoms: Union[Atoms, List[Atom], None] = None,
atoms: Union[autode.atoms.Atoms, List[Atom], None] = None,
charge: int = 0,
mult: int = 1,
box: Optional[Box] = None
Expand Down Expand Up @@ -55,7 +58,7 @@ def ase_atoms(self) -> 'ase.atoms.Atoms':
Returns:
(ase.atoms.Atoms): ASE atoms
"""
_atoms = Atoms(symbols=[atom.label for atom in self.atoms],
_atoms = ase.atoms.Atoms(symbols=[atom.label for atom in self.atoms],
positions=self.coordinates,
pbc=self.box is not None)

Expand Down
7 changes: 4 additions & 3 deletions mlptrain/configurations/configuration_set.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import mlptrain
import os
import numpy as np
from time import time
Expand Down Expand Up @@ -447,12 +448,12 @@ def plumed_coordinates(self) -> Optional[np.ndarray]:
n_cvs_set.add(len(config.plumed_coordinates))

if len(n_cvs_set) == 0:
logger.info(f'PLUMED coordinates not defined - returning None')
logger.info('PLUMED coordinates not defined - returning None')
return None

elif len(n_cvs_set) != 1:
logger.info(f'Number of CVs differ between configurations - '
f'returning None')
logger.info('Number of CVs differ between configurations - '
'returning None')
return None

n_cvs = n_cvs_set.pop()
Expand Down
1 change: 1 addition & 0 deletions mlptrain/configurations/plotting.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import mlptrain
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
Expand Down
Loading

0 comments on commit 41fbb2c

Please sign in to comment.