Open-Catalyst-Project / AdsorbML

Corresponding dataset and tools for the AdsorbML manuscript.
MIT License
36 stars 5 forks source link

Different slabs for the same miller index #12

Open gihanpanapitiya opened 10 months ago

gihanpanapitiya commented 10 months ago

I am following the example at adsorbml_walkthrough.ipynb. Do you know why we get different slabs for the same miller index? I want to select the slab that has the same number of layers as that of the bulk. Is there a way to do this?

abhshkdz commented 10 months ago

Do you know why we get different slabs for the same miller index?

There could be multiple slabs for a miller index because of different shifts and if the top and bottom aren't symmetric.

No. of layers should be the same though; let us know if you find otherwise.

gihanpanapitiya commented 10 months ago

I obtain slabs as below.

bulk = Bulk(bulk_atoms=slab_ats)
slabs = Slab.from_bulk_get_specific_millers(bulk = bulk, specific_millers=(0,0,1))

slab_ats is an ase.atoms.Atoms object,

Atoms(symbols='Cu64', pbc=True, cell=[[10.21062183380127, 0.0, 0.0], [5.105310916900635, 8.842658042907715, 0.0], [0.0, 0.0, 32.25270462036133]], tags=..., constraint=FixAtoms(indices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]), calculator=SinglePointCalculator(...))

which looks as below.

Screenshot 2023-12-17 at 9 03 54 PM

slabs contain 4 slabs. They visualize as below.

Screenshot 2023-12-17 at 9 07 04 PM Screenshot 2023-12-17 at 9 07 13 PM Screenshot 2023-12-17 at 9 08 58 PM Screenshot 2023-12-17 at 9 09 07 PM

So, only slab[2] has 4 layers as that of the slab_ats.

abhshkdz commented 10 months ago

That definitely looks buggy, especially the gap between some of the layers.. Could you share the atoms object for slab_ats so we can try debugging at our end?

@mshuaibii any thoughts?

mshuaibii commented 10 months ago

@gihanpanapitiya Where did you create slab_ats from? The Bulk class expects a conventional unit cell to be supplied for slabs to be properly created. I suspect something weird is going on either here or here because of the slab being fed in as a bulk structure. If you can share the atoms object for slab_ats directly or describe how to recreate it, I can look closer on my end.

gihanpanapitiya commented 10 months ago

Thanks! The issue can be reproduced using the following code.

from ocdata.core import Bulk, Slab
from ase.build import fcc111

slab_ats = fcc111('Cu', size=(4, 4, 4), vacuum=10.0)
bulk = Bulk(bulk_atoms=slab_ats)
slabs = Slab.from_bulk_get_specific_millers(bulk = bulk, specific_millers=(0,0,1))
mshuaibii commented 10 months ago

I see. Yeah, it looks like you've created a 111 surface, and then are feeding that into the Slab creator, which is not the correct use case. You should feed in a bulk structure, as follows:

from ocdata.core import Bulk, Slab

bulk = Bulk(
    bulk_id_from_db=12, # this corresponds to the Cu bulk structure.
    bulk_db_path="/path/to/ocdata/databases/pkls/bulks.pkl"
)
slabs = Slab.from_bulk_get_specific_millers(bulk = bulk, specific_millers=(0,0,1))

If you are interested in other bulk structures, you can look for them in the following database - https://github.com/Open-Catalyst-Project/Open-Catalyst-Dataset/blob/main/ocdata/databases/pkls/bulks.pkl.

gihanpanapitiya commented 10 months ago

If we want to use a bulk not in /path/to/ocdata/databases/pkls/bulks.pkl is there a particular way we should prepare our own bulk object so that it's compatible with Slab.from_bulk_get_specific_millers()?

gihanpanapitiya commented 10 months ago

We would like to use our own slabs to find the heuristic placements. Is the method below a valid way to use AdsorbateSlabConfig? I am not very sure about step 2 and step 3. Particularly about what values should be used for specific_millers. Even though my Cu slab has a 111 surface using (0,0,1) for specific_millers seems to produce structures that look correct.

from ocdata.core import Adsorbate, AdsorbateSlabConfig, Bulk, Slab
import ase.build as build

# step 1 - create the slab
ats = build.fcc111('Cu', (4, 4, 4))
ats.center(vacuum=13.0, axis=2)

# step 2 - create the bulk
bulk = Bulk(bulk_atoms=ats)

# step 3 - create the Slab object
slabs = Slab.from_bulk_get_specific_millers(bulk=bulk, specific_millers=(0,0,1))

# step 4 - find the heuristic placements
adsorbate_smiles = "*CO"
adsorbate = Adsorbate(adsorbate_smiles_from_db=adsorbate_smiles,
                      adsorbate_db_path = "../Open-Catalyst-Dataset/ocdata/databases/pkls/adsorbates.pkl")

heuristic_adslabs = AdsorbateSlabConfig(slabs[0], adsorbate, mode="heuristic")