Practice
Turn the geometry into a reproducible model
ASE can build and manipulate an atomistic slab, but the script must still state the crystal, orientation, termination, cell, site, constraints, and numerical tests that define the model.
Translate each scientific choice into a parameter
The Atomic Simulation Environment (ASE) represents atoms, cells, periodic boundary conditions, constraints, calculators, and file formats in a scriptable Python interface. It does not decide which physical model is appropriate; that remains part of the scientific work. [1]
| Scientific choice | ASE representation | What must be recorded |
|---|---|---|
| Bulk structure and metric | builder, element, a, and for HCP c | Source and state of the lattice parameters |
| Orientation and termination | facet-specific builder or surface() | Indices, input bulk cell, and exposed termination |
| Surface cell and thickness | size=(n₁,n₂,nlayers) | In-plane vectors and atom-bearing layer count |
| Adsorption geometry | named keyword or explicit Cartesian (x,y) | Initial lateral site, height, and molecular orientation |
| Bulk-like support | FixAtoms or another constraint | Exactly which atoms were constrained |
ASE provides specialized helpers for common low-index surfaces and a general surface builder for other orientations. Supported named adsorption sites depend on the helper; a physically meaningful site is not automatically an ASE keyword. [2]
Build one complete structure explicitly
This example creates a \(3\times3\), four-layer Cu(111) slab, starts H at an FCC hollow, adds 12 Å of vacuum on each side of the complete slab–adsorbate structure, and fixes the bottom metal layer. The numerical lattice constant and starting height are explicit, illustrative inputs; replace them with sourced values appropriate to the intended calculation. ASE’s surface builders assign positive integer tags to substrate layers, beginning with 1 at the outermost layer. [2]
import ase
import numpy as np
from ase.build import add_adsorbate, fcc111
from ase.constraints import FixAtoms
from ase.io import write
a = 3.615 # Å; illustrative input—replace and cite for production work
slab = fcc111("Cu", size=(3, 3, 4), a=a, vacuum=None)
add_adsorbate(slab, "H", height=1.2, position="fcc")
slab.center(vacuum=12.0, axis=2)
# Surface builders tag the outermost metal layer 1 and count inward.
bottom_tag = max(slab.get_tags())
slab.set_constraint(FixAtoms(mask=slab.get_tags() == bottom_tag))
slab.info["model"] = {
"ase_version": ase.__version__,
"facet": "Cu(111)",
"lattice_constant_A": a,
"lattice_parameter_source": "illustrative teaching input",
"initial_site": "fcc",
"initial_height_A": 1.2,
}
write("cu111_h_initial.traj", slab)
print("ASE:", ase.__version__)
print("cell / Å:\n", slab.cell.array)
print("PBC:", slab.pbc)
print("tags:", np.unique(slab.get_tags(), return_counts=True))
Adding the adsorbate before calling center() makes the requested vacuum apply to the complete structure rather than only to the clean slab. An explicit lattice parameter prevents the geometry from silently changing with a library default or database update. The script records, but does not claim, that 3.615 Å is the correct bulk parameter for a particular state or that 1.2 Å is a relaxed H–surface distance.
Keep lateral site and vertical height separate
add_adsorbate() accepts either a builder-supported site name or an absolute Cartesian \((x,y)\) position. Its offset argument is expressed in surface-cell repeats. For a molecule, mol_index selects the atom placed at that reference point; orienting the rest of the molecule is the user’s responsibility. [2]
In ASE 3.24.0, height is added to the \(z\) coordinate of the stored top-layer atom. If that metadata is absent, ASE finds and caches the slab atom with the largest \(z\). It does not infer a chemistry-dependent bond length or a local height above a lower terrace atom. [3]
For a site given by atlas fractional coordinates \((u,v)\), first verify that the atlas and ASE structures use the same vector order, handedness, and surface-cell origin. If they do, convert through the actual ASE in-plane vectors and add that origin before passing the Cartesian position to ASE:
u, v = 1 / 3, 1 / 3
origin_xy = np.array([0.0, 0.0]) # ASE origin matching the atlas origin
xy = origin_xy + u * slab.cell[0, :2] + v * slab.cell[1, :2]
# Use a deliberately chosen initial z for corrugated or stepped surfaces.
# add_adsorbate(slab, "H", height=..., position=xy)
If the origins or cell conventions differ, map the coordinate with the corresponding affine cell transformation instead of copying \((u,v)\). On a corrugated surface, construct the local support geometry explicitly and inspect the resulting Cartesian position. The atlas’s shared marker height is only a visualization convention; it is not an input recommendation.
Inspect the structure and make assumptions executable
A successful constructor call proves only that an Atoms object exists. View the structure from above and from the side, then check its invariants in code:
metal = slab[slab.get_tags() > 0]
z_levels = np.unique(np.round(metal.positions[:, 2], 5))
assert tuple(bool(x) for x in slab.pbc) == (True, True, False)
assert len(z_levels) == 4
assert np.count_nonzero(slab.get_tags() == bottom_tag) == 9
assert slab.cell.area(2) > 0
print("metal layer z / Å:", z_levels)
print("vacuum-axis length / Å:", slab.cell.lengths()[2])
Inspect the termination, layer sequence, in-plane vectors, atom count, constraints, adsorbate orientation, and shortest periodic adsorbate-image distance. Assertions should encode properties that are invariant for the intended model, not incidental ordering of atoms in a file.
Converge the quantity you intend to report
There is no universal safe layer count or vacuum thickness. Change one approximation at a time and monitor the quantity used in the conclusion. Surface-slab construction and convergence require consistent bulk and slab references, particularly for surface energies. [4]
| Test | Change | Monitor |
|---|---|---|
| Bulk reference | lattice parameter, cutoff, k-point density | energy per atom and stress |
| Slab thickness | number of atomic layers | surface/adsorption energy and central-layer behaviour |
| Vacuum | cell length normal to the surface | energy, potential, work function, and image interaction |
| Lateral cell | surface supercell | coverage and adsorbate-image interaction |
| Relaxed depth | fixed versus mobile layers | forces and near-surface geometry |
| Reciprocal sampling | k-point density scaled with cell size | energies, forces, and metallic states |
A symmetric slab has equivalent faces by construction. A one-sided adsorbate usually makes the slab asymmetric and can create a dipole normal to the surface under three-dimensional periodic electrostatics. Vacuum alone does not necessarily remove the artificial field; use and document the correction appropriate to the chosen calculator. [5]
Save enough information to reproduce the model
Keep the initial and relaxed structures, the generating script, calculator input, and software environment together. A useful record includes:
- ASE and calculator versions, plus pseudopotential or basis identifiers;
- element or composition, lattice parameters, and their source;
- indices, termination, reconstruction, in-plane vectors, and slab thickness;
- vacuum, periodic boundary conditions, constraints, and dipole treatment;
- adsorbate identity, coverage, starting coordinate, height, and orientation;
- electronic settings and the convergence evidence for the reported quantity;
- initial and final geometries when relaxation changes the named site.
Pin dependencies in a lock file or environment specification when the work must be rerun exactly. Cite the ASE paper for the software and the version-relevant official documentation or source for API behaviour. A short script plus a structure file is substantially more reproducible than either one alone.
Sources
References
- (2017). The Atomic Simulation Environment—a Python library for working with atoms. Journal of Physics: Condensed Matter 29, 273002. doi:10.1088/1361-648X/aa680e.
- . Surfaces. ASE documentation. Official documentation. Accessed 2026-07-13.
- (2024). Surface builder implementation (ASE 3.24.0). ASE source code, version 3.24.0. Version-pinned source.
- (2013). Efficient creation and convergence of surface slabs. Surface Science 617, 53–59. doi:10.1016/j.susc.2013.05.016. Open manuscript.
- (1999). Dipole correction for surface supercell calculations. Physical Review B 59, 12301–12304. doi:10.1103/PhysRevB.59.12301.