Source code for scgo.surface.presets
"""Reusable slab and surface presets for runners and benchmarks."""
from __future__ import annotations
import numpy as np
from ase import Atoms
from ase.build import graphene
from scgo.initialization.initialization_config import CONNECTIVITY_FACTOR
from scgo.surface.config import SurfaceSystemConfig
from scgo.surface.pbc import normalize_slab_pbc
DEFAULT_GRAPHITE_SLAB_LAYERS = 5
DEFAULT_GRAPHITE_SLAB_REPEAT_XY = 4
DEFAULT_GRAPHITE_SLAB_VACUUM = 12.0
# Graphite interlayer distance (AB stacking ~3.35 Å)
GRAPHITE_INTERLAYER_DISTANCE = 3.35
def build_graphite_slab(
*,
layers: int = DEFAULT_GRAPHITE_SLAB_LAYERS,
vacuum: float = DEFAULT_GRAPHITE_SLAB_VACUUM,
repeat_xy: int = DEFAULT_GRAPHITE_SLAB_REPEAT_XY,
) -> Atoms:
"""Build a graphite slab with periodic in-plane boundary conditions.
Creates a multi-layer graphite slab with correct interlayer spacing
(~3.35 Angstroms). Each layer is a graphene sheet, and layers are stacked
with the graphite interlayer distance.
"""
if layers < 1:
raise ValueError(f"layers must be >= 1, got {layers}")
single_layer = graphene(formula="C2", vacuum=0.0)
single_layer = single_layer.repeat((repeat_xy, repeat_xy, 1))
if layers == 1:
single_layer.center(vacuum=vacuum, axis=2)
normalize_slab_pbc(single_layer)
return single_layer
all_positions = single_layer.get_positions().copy()
all_symbols = single_layer.get_chemical_symbols()
for layer_idx in range(1, layers):
layer_positions = single_layer.get_positions().copy()
layer_positions[:, 2] += layer_idx * GRAPHITE_INTERLAYER_DISTANCE
all_positions = np.vstack([all_positions, layer_positions])
all_symbols.extend(single_layer.get_chemical_symbols())
slab = Atoms(symbols=all_symbols, positions=all_positions)
slab.set_cell(single_layer.get_cell())
cell = slab.get_cell()
cell[2, 2] = (layers - 1) * GRAPHITE_INTERLAYER_DISTANCE + vacuum
slab.set_cell(cell)
positions = slab.get_positions()
positions[:, 2] += vacuum / 2
slab.set_positions(positions)
normalize_slab_pbc(slab)
return slab
[docs]
def make_graphite_surface_config(
*,
slab_layers: int = DEFAULT_GRAPHITE_SLAB_LAYERS,
slab_repeat_xy: int = DEFAULT_GRAPHITE_SLAB_REPEAT_XY,
vacuum: float = DEFAULT_GRAPHITE_SLAB_VACUUM,
structure_connectivity_factor: float = CONNECTIVITY_FACTOR,
) -> SurfaceSystemConfig:
"""Graphite slab preset (top layer relaxes with adsorbate during GO/NEB)."""
slab = build_graphite_slab(
layers=slab_layers, vacuum=vacuum, repeat_xy=slab_repeat_xy
)
return SurfaceSystemConfig(
slab=slab,
adsorption_height_min=0.5,
adsorption_height_max=1.0,
fix_all_slab_atoms=False,
n_relax_top_slab_layers=1,
comparator_use_mic=True,
max_placement_attempts=1000,
structure_connectivity_factor=structure_connectivity_factor,
)
__all__ = [
"DEFAULT_GRAPHITE_SLAB_LAYERS",
"DEFAULT_GRAPHITE_SLAB_REPEAT_XY",
"DEFAULT_GRAPHITE_SLAB_VACUUM",
"build_graphite_slab",
"make_graphite_surface_config",
]