Skip to content

Commit d76d09f

Browse files
committed
Add support for specifying adsorption positions in adsorbate calculations
1 parent 0090d59 commit d76d09f

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

vsh/scripts/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ def adsorb(subparsers):
148148
subp_adsorb.add_argument("-c","--coverage",type=int,nargs=3,default=[1, 1, 1],help="Adsorbate coverage")
149149
subp_adsorb.add_argument("-b","--both",action='store_true',help="Adsorbate on both surfaces")
150150
subp_adsorb.add_argument("-o", "--output", type=str, default=None, help="Output basename")
151+
subp_adsorb.add_argument("-p", "--positions", choices=['all', 'ontop', 'bridge', 'hollow'], default='all', help="Adsorption sites")
152+
subp_adsorb.add_argument("-P", "--plane", type=int, nargs=3, help="Miller plane required for adsorbing on both surfaces")
151153

152154
def alchemy(subparsers):
153155

vsh/scripts/adsorb.py

+33-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,28 @@
11
from pymatgen.analysis.adsorption import AdsorbateSiteFinder
22
from pymatgen.core.structure import Molecule, Structure
3+
from pymatgen.core.surface import Slab
34
from pymatgen.io.vasp.inputs import Poscar
45

6+
7+
def slab_from_structure(miller: list[int], structure: Structure) -> Slab:
8+
'''
9+
Returns a pymatgen.core.surface.Slab from a pymatgen structure
10+
'''
11+
import numpy as np
12+
13+
#if miller is None, raise error
14+
if miller is None:
15+
raise ValueError('miller index is required')
16+
17+
return Slab(lattice=structure.lattice,
18+
species=structure.species_and_occu,
19+
coords=structure.frac_coords,
20+
miller_index=miller,
21+
oriented_unit_cell=structure,
22+
shift=0,
23+
scale_factor=np.eye(3, dtype=int),
24+
site_properties=structure.site_properties)
25+
526
def structure_from_file(filename: str) -> Structure:
627
'''
728
Creates a pymatgen structure from a file
@@ -24,23 +45,23 @@ def get_chemical_formula(structure: Structure) -> str:
2445
'''
2546
return structure.composition.reduced_formula
2647

27-
def add_adsorbate_single(structure: Structure, adsorbate: Molecule, coverage: list[int] = [1, 1, 1], distance: float = 1.0) -> list[Structure]:
48+
def add_adsorbate_single(structure: Structure, adsorbate: Molecule, coverage: list[int] = [1, 1, 1], distance: float = 1.0, positions=('ontop', 'bridge', 'hollow')) -> list[Structure]:
2849
'''
2950
Finds all adsorption sites on a structure and adsorbs the adsorbate at each site. Returns a list of adsorbed structures.
3051
'''
3152

3253
asf = AdsorbateSiteFinder(structure)
33-
ads_structs = asf.generate_adsorption_structures(adsorbate, repeat=coverage, find_args={"distance": distance}) # edit later
54+
ads_structs = asf.generate_adsorption_structures(adsorbate, repeat=coverage, find_args={"distance": distance, "positions": positions}) # edit later
3455

3556
return ads_structs
3657

37-
def add_adsorbate_on_both_surfaces(structure: Structure, adsorbate: Molecule, coverage: list[int] = [1, 1, 1], distance: float = 1.0) -> list[Structure]:
58+
def add_adsorbate_on_both_surfaces(structure: Structure, adsorbate: Molecule, miller_plane: list[int], coverage: list[int] = [1, 1, 1], distance: float = 1.0, positions=('ontop', 'bridge', 'hollow')) -> list[Structure]:
3859
'''
3960
Finds all adsorption sites on a structure and adsorbs the adsorbate at each site. Returns a list of adsorbed structures.
4061
'''
41-
42-
asf = AdsorbateSiteFinder(structure)
43-
ads_structs = asf.adsorb_both_surfaces(adsorbate, repeat=coverage, find_args={"distance": distance}) # edit later
62+
slab = slab_from_structure(miller=miller_plane, structure=structure)
63+
asf = AdsorbateSiteFinder(slab)
64+
ads_structs = asf.adsorb_both_surfaces(adsorbate, repeat=coverage, find_args={"distance": distance, "positions": positions}) # edit later
4465

4566
return ads_structs
4667

@@ -59,10 +80,14 @@ def create_adsorbed_structure(args):
5980
structure = structure_from_file(args.input)
6081
adsorbate = adsorbate_from_file(args.adsorbate)
6182

83+
#if positions = 'all', then set positions to be positions=('ontop', 'bridge', 'hollow')
84+
if args.positions == 'all':
85+
args.positions = ('ontop', 'bridge', 'hollow')
86+
6287
if args.both:
63-
ads_structs = add_adsorbate_on_both_surfaces(structure, adsorbate, coverage=args.coverage, distance=args.distance)
88+
ads_structs = add_adsorbate_on_both_surfaces(structure, adsorbate, miller_plane=args.plane, coverage=args.coverage, distance=args.distance, positions=args.positions)
6489
else:
65-
ads_structs = add_adsorbate_single(structure, adsorbate, coverage=args.coverage, distance=args.distance)
90+
ads_structs = add_adsorbate_single(structure, adsorbate, coverage=args.coverage, distance=args.distance, positions=args.positions)
6691

6792
poscars = [ Poscar(ads_struct, sort_structure=True) for ads_struct in ads_structs ]
6893

0 commit comments

Comments
 (0)