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

add better solvent placement logic #835

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
19 changes: 12 additions & 7 deletions src/fairchem/data/oc/core/adsorbate_slab_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,20 +489,22 @@ def custom_tile_atoms(atoms: ase.Atoms):
return new_atoms


def get_interstitial_distances(adsorbate_slab_config: ase.Atoms):
def get_interstitial_distances(adsorbate_slab_config: ase.Atoms, overlap_tag=2):
mshuaibii marked this conversation as resolved.
Show resolved Hide resolved
"""
Check to see if there is any atomic overlap between surface atoms
and adsorbate atoms.
Check to see if there is any atomic overlap between atoms with a particular
tag and all other atoms. Used to check overlap between adsorbate and
surface atoms.

Args:
adsorbate_slab_configuration (ase.Atoms): an slab atoms object with an
adsorbate placed
overlap_tag (int): Tag to check overlap with

Returns:
(bool): True if there is atomic overlap, otherwise False
"""
ads_slab_config = adsorbate_slab_config.copy()
mask = adsorbate_slab_config.get_tags() == 2
mask = adsorbate_slab_config.get_tags() == overlap_tag
adsorbate_atoms = adsorbate_slab_config[mask]
adsorbate_com = adsorbate_atoms.get_center_of_mass()

Expand All @@ -514,7 +516,7 @@ def get_interstitial_distances(adsorbate_slab_config: ase.Atoms):
adsorbate_atoms = ads_slab_config[mask]
adsorbate_elements = adsorbate_atoms.get_chemical_symbols()

mask = ads_slab_config.get_tags() == 1
mask = ads_slab_config.get_tags() != overlap_tag
mshuaibii marked this conversation as resolved.
Show resolved Hide resolved
surface_atoms = ads_slab_config[mask]
surface_elements = surface_atoms.get_chemical_symbols()

Expand All @@ -537,17 +539,20 @@ def get_interstitial_distances(adsorbate_slab_config: ase.Atoms):
return post_radial_distances


def there_is_overlap(adsorbate_slab_config: ase.Atoms):
def there_is_overlap(adsorbate_slab_config: ase.Atoms, overlap_tag=2):
mshuaibii marked this conversation as resolved.
Show resolved Hide resolved
"""
Check to see if there is any atomic overlap between surface atoms
and adsorbate atoms.

Args:
adsorbate_slab_configuration (ase.Atoms): an slab atoms object with an
adsorbate placed
overlap_tag (int): Tag to check overlap with

Returns:
(bool): True if there is atomic overlap, otherwise False
"""
post_radial_distances = get_interstitial_distances(adsorbate_slab_config)
post_radial_distances = get_interstitial_distances(
adsorbate_slab_config, overlap_tag
)
return not all(np.array(post_radial_distances) >= 0)
29 changes: 19 additions & 10 deletions src/fairchem/data/oc/core/interface_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import ase.io
import numpy as np
from fairchem.data.oc.core.adsorbate_slab_config import there_is_overlap
from fairchem.data.oc.core.multi_adsorbate_slab_config import (
MultipleAdsorbateSlabConfig,
)
Expand Down Expand Up @@ -57,9 +58,6 @@ class InterfaceConfig(MultipleAdsorbateSlabConfig):
well as the inter-adsorbate distance.
vacuum_size: int
Size of vacuum layer to add to both ends of the resulting atoms object.
solvent_interstitial_gap: float
Minimum distance, in Angstroms, between the solvent environment and the
adsorbate-slab environment.
solvent_depth: float
Volume depth to be used to pack solvents inside.
pbc_shift: float
Expand Down Expand Up @@ -101,7 +99,6 @@ def __init__(
num_configurations: int = 1,
interstitial_gap: float = 0.1,
vacuum_size: int = 15,
solvent_interstitial_gap: float = 2,
solvent_depth: float = 8,
pbc_shift: float = 0.0,
packmol_tolerance: float = 2,
Expand All @@ -120,7 +117,6 @@ def __init__(
self.ions = ions
self.vacuum_size = vacuum_size
self.solvent_depth = solvent_depth
self.solvent_interstitial_gap = solvent_interstitial_gap
self.pbc_shift = pbc_shift
self.packmol_tolerance = packmol_tolerance

Expand Down Expand Up @@ -159,12 +155,25 @@ def create_interface_on_sites(
solvent_ions_atoms = self.create_packmol_atoms(geometry, n_solvent_mols)
solvent_ions_atoms.set_cell(cell)

max_z = atoms.positions[:, 2].max() + self.solvent_interstitial_gap
translation_vec = cell[2]
translation_vec[2] = max_z
solvent_ions_atoms.translate(translation_vec)
# Place the solvent+ion environment at the interface with the
# adsorbate-slab envrionment. Iteratively tile the solvated atoms
# to ensure no atomic overlap with the adsorbate+slab.
# Take max slab height as starting point
max_slab_z = atoms[atoms.get_tags() == 1].positions[:, 2].max()
translation_vec = cell[2] / np.linalg.norm(cell[2])
overlap = True
while overlap:
_tv = translation_vec.copy()
_tv *= max_slab_z

_solvent_ions_atoms = solvent_ions_atoms.copy()
_solvent_ions_atoms.translate(_tv)

adslab = atoms.copy()
interface_atoms = adslab + _solvent_ions_atoms
overlap = there_is_overlap(interface_atoms, overlap_tag=3)
max_slab_z += 0.5 # iteratively tile cell

interface_atoms = atoms + solvent_ions_atoms
interface_atoms.center(vacuum=self.vacuum_size, axis=2)
interface_atoms.wrap()

Expand Down
1 change: 1 addition & 0 deletions src/fairchem/data/oc/utils/vasp_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,5 @@
"smass": 0,
"tebeg": 1000,
"potim": 2,
"isym": 0,
}
3 changes: 0 additions & 3 deletions tests/data/oc/tests/test_interface_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ def load_data(request):
request.cls.ions = ions
request.cls.vacuum = 15
request.cls.solvent_depth = 10
request.cls.solvent_interstitial_gap = 2


@pytest.mark.usefixtures("load_data")
Expand All @@ -38,7 +37,6 @@ def test_num_configurations(self):
self.solvent,
self.ions,
vacuum_size=self.vacuum,
solvent_interstitial_gap=self.solvent_interstitial_gap,
solvent_depth=self.solvent_depth,
num_configurations=10,
)
Expand All @@ -60,7 +58,6 @@ def test_solvent_density(self):
self.solvent,
self.ions,
vacuum_size=self.vacuum,
solvent_interstitial_gap=self.solvent_interstitial_gap,
solvent_depth=self.solvent_depth,
num_configurations=10,
)
Expand Down