-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #208 from arosen93/gulp
Add `GULP` recipes
- Loading branch information
Showing
13 changed files
with
719 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
dependencies: | ||
- psi4::psi4 | ||
- conda-forge::dftbplus==22.2 | ||
- conda-forge::dftbplus==22.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Recipes for GULP""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
"""Core recipes for GULP""" | ||
from __future__ import annotations | ||
|
||
import warnings | ||
from dataclasses import dataclass, field | ||
from typing import Any, Dict | ||
|
||
from ase.atoms import Atoms | ||
from ase.calculators.gulp import GULP | ||
from jobflow import Maker, job | ||
|
||
from quacc.schemas.calc import summarize_run | ||
from quacc.util.basics import merge_dicts | ||
from quacc.util.calc import run_calc | ||
|
||
|
||
@dataclass | ||
class StaticJob(Maker): | ||
""" | ||
Class to carry out a single-point calculation. | ||
Note: 'Conditions' are not yet natively supported. | ||
Parameters | ||
---------- | ||
name | ||
Name of the job. | ||
gfnff | ||
True if (p)GFN-FF should be used; False if not. | ||
library | ||
Filename of the potential library file, if required. | ||
keyword_swaps | ||
Dictionary of custom keyword swap kwargs for the calculator. | ||
option_swaps | ||
Dictionary of custom option swap kwargs for the calculator. | ||
""" | ||
|
||
name: str = "GULP-Static" | ||
gfnff: bool = True | ||
library: str = None | ||
keyword_swaps: Dict[str, Any] = field(default_factory=dict) | ||
option_swaps: Dict[str, Any] = field(default_factory=dict) | ||
|
||
@job | ||
def make(self, atoms: Atoms) -> Dict[str, Any]: | ||
""" | ||
Make the run. | ||
Parameters | ||
---------- | ||
atoms | ||
.Atoms object | ||
Returns | ||
------- | ||
Dict | ||
Summary of the run. | ||
""" | ||
|
||
default_keywords = { | ||
"gfnff": self.gfnff, | ||
"gwolf": True if self.gfnff and atoms.pbc.any() else False, | ||
} | ||
default_options = { | ||
"dump every gulp.res": True, | ||
"output cif gulp.cif": True if atoms.pbc.any() else False, | ||
"output xyz gulp.xyz": False if atoms.pbc.any() else True, | ||
} | ||
|
||
keywords = merge_dicts( | ||
default_keywords, self.keyword_swaps, remove_none=True, remove_false=True | ||
) | ||
options = merge_dicts( | ||
default_options, self.option_swaps, remove_none=True, remove_false=True | ||
) | ||
|
||
gulp_keywords = " ".join(list(keywords.keys())) | ||
gulp_options = list(options.keys()) | ||
|
||
atoms.calc = GULP(keywords=gulp_keywords, options=gulp_options) | ||
new_atoms = run_calc( | ||
atoms, geom_file="gulp.cif" if atoms.pbc.any() else "gulp.xyz" | ||
) | ||
summary = summarize_run( | ||
new_atoms, input_atoms=atoms, additional_fields={"name": self.name} | ||
) | ||
|
||
return summary | ||
|
||
|
||
@dataclass | ||
class RelaxJob(Maker): | ||
""" | ||
Class to carry out a single-point calculation. | ||
Note: 'Conditions' are not yet natively supported. | ||
Parameters | ||
---------- | ||
name | ||
Name of the job. | ||
gfnff | ||
True if (p)GFN-FF should be used; False if not. | ||
library | ||
Filename of the potential library file, if required. | ||
volume_relax | ||
True if the volume should be relaxed; False if not. | ||
keyword_swaps | ||
Dictionary of custom keyword swap kwargs for the calculator. | ||
option_swaps | ||
Dictionary of custom option swap kwargs for the calculator. | ||
""" | ||
|
||
name: str = "GULP-Relax" | ||
gfnff: bool = True | ||
library: str = None | ||
volume_relax: bool = True | ||
keyword_swaps: Dict[str, Any] = field(default_factory=dict) | ||
option_swaps: Dict[str, Any] = field(default_factory=dict) | ||
|
||
@job | ||
def make(self, atoms: Atoms) -> Dict[str, Any]: | ||
""" | ||
Make the run. | ||
Parameters | ||
---------- | ||
atoms | ||
.Atoms object | ||
Returns | ||
------- | ||
Dict | ||
Summary of the run. | ||
""" | ||
if self.volume_relax and not atoms.pbc.any(): | ||
warnings.warn("Volume relaxation requested but no PBCs found. Ignoring.") | ||
self.volume_relax = False | ||
|
||
default_keywords = { | ||
"opti": True, | ||
"gfnff": self.gfnff, | ||
"gwolf": True if self.gfnff and atoms.pbc.any() else False, | ||
"conp": True if self.volume_relax and atoms.pbc.any() else False, | ||
"conv": True if not self.volume_relax or not atoms.pbc.any() else False, | ||
} | ||
default_options = { | ||
"dump every gulp.res": True, | ||
"output cif gulp.cif": True if atoms.pbc.any() else False, | ||
"output xyz gulp.xyz": False if atoms.pbc.any() else True, | ||
} | ||
|
||
keywords = merge_dicts( | ||
default_keywords, self.keyword_swaps, remove_none=True, remove_false=True | ||
) | ||
options = merge_dicts( | ||
default_options, self.option_swaps, remove_none=True, remove_false=True | ||
) | ||
|
||
gulp_keywords = " ".join(list(keywords.keys())) | ||
gulp_options = list(options.keys()) | ||
|
||
atoms.calc = GULP(keywords=gulp_keywords, options=gulp_options) | ||
new_atoms = run_calc( | ||
atoms, geom_file="gulp.cif" if atoms.pbc.any() else "gulp.xyz" | ||
) | ||
|
||
if not new_atoms.calc.get_opt_state(): | ||
raise ValueError("Optimization did not converge!") | ||
|
||
summary = summarize_run( | ||
new_atoms, input_atoms=atoms, additional_fields={"name": self.name} | ||
) | ||
|
||
return summary |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import os | ||
from unittest import mock | ||
|
||
import numpy as np | ||
import pytest | ||
from ase.atoms import Atoms | ||
from ase.calculators.gulp import GULP | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def mock_settings_env_vars(): | ||
with mock.patch.dict(os.environ, {"GULP_LIB": "."}): | ||
yield | ||
|
||
|
||
def mock_get_potential_energy(self, **kwargs): | ||
# Instead of running .get_potential_energy(), we mock it by attaching | ||
# dummy results to the atoms object and returning a fake energy. This | ||
# works because the real atoms.get_potential_energy() takes one argument | ||
# (i.e. self) and that self object is the atoms object. | ||
e = -1.0 | ||
self.calc.results = { | ||
"energy": e, | ||
"forces": np.array([[0.0, 0.0, 0.0]] * len(self)), | ||
} | ||
return e | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def patch_get_potential_energy(monkeypatch): | ||
# Monkeypatch the .get_potential_energy() method of the .Atoms object so | ||
# we aren't running the actual calculation during testing. | ||
monkeypatch.setattr(Atoms, "get_potential_energy", mock_get_potential_energy) | ||
|
||
|
||
def mock_get_opt_state(self, **kwargs): | ||
# Instead of running GULP and getting the opt state, we'll just mock | ||
# it as true | ||
|
||
self.get_opt_state = True | ||
|
||
return True | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def patch_get_opt_state(monkeypatch): | ||
# Monkeypatch the .get_opt_state() method of the GULP calculator object so | ||
# we aren't fetching the actual state | ||
monkeypatch.setattr(GULP, "get_opt_state", mock_get_opt_state) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
data_cif | ||
|
||
_audit_creation_method 'generated by GULP' | ||
|
||
_symmetry_space_group_name_H-M '(unknown) ' | ||
_symmetry_Int_Tables_number 1 | ||
|
||
_symmetry_equiv_pos_site_id | ||
_symmetry_equiv_pos_as_xyz | ||
_cell_length_a 5.1053 | ||
_cell_length_b 5.1053 | ||
_cell_length_c 5.1053 | ||
_cell_angle_alpha 60.0000 | ||
_cell_angle_beta 60.0000 | ||
_cell_angle_gamma 60.0000 | ||
|
||
loop_ | ||
_atom_site_label | ||
_atom_site_fract_x | ||
_atom_site_fract_y | ||
_atom_site_fract_z | ||
_atom_site_occupancy | ||
Cu 0.00000 0.00000 0.00000 1.0000 | ||
Cu 0.00000 0.00000 0.50000 1.0000 | ||
Cu 0.00000 0.50000 0.00000 1.0000 | ||
Cu 1.00000 0.50000 0.50000 1.0000 | ||
Cu 0.50000 0.00000 0.00000 1.0000 | ||
Cu 0.50000 1.00000 0.50000 1.0000 | ||
Cu 0.50000 0.50000 0.00000 1.0000 | ||
Cu 0.50000 0.50000 0.50000 1.0000 |
Oops, something went wrong.