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 choiceASE representationWhat must be recorded
Bulk structure and metricbuilder, element, a, and for HCP cSource and state of the lattice parameters
Orientation and terminationfacet-specific builder or surface()Indices, input bulk cell, and exposed termination
Surface cell and thicknesssize=(n₁,n₂,nlayers)In-plane vectors and atom-bearing layer count
Adsorption geometrynamed keyword or explicit Cartesian (x,y)Initial lateral site, height, and molecular orientation
Bulk-like supportFixAtoms or another constraintExactly 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]

TestChangeMonitor
Bulk referencelattice parameter, cutoff, k-point densityenergy per atom and stress
Slab thicknessnumber of atomic layerssurface/adsorption energy and central-layer behaviour
Vacuumcell length normal to the surfaceenergy, potential, work function, and image interaction
Lateral cellsurface supercellcoverage and adsorbate-image interaction
Relaxed depthfixed versus mobile layersforces and near-surface geometry
Reciprocal samplingk-point density scaled with cell sizeenergies, 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

  1. A. H. Larsen et al. (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.
  2. Atomic Simulation Environment contributors. Surfaces. ASE documentation. Official documentation. Accessed 2026-07-13.
  3. Atomic Simulation Environment contributors (2024). Surface builder implementation (ASE 3.24.0). ASE source code, version 3.24.0. Version-pinned source.
  4. W. Sun and G. Ceder (2013). Efficient creation and convergence of surface slabs. Surface Science 617, 53–59. doi:10.1016/j.susc.2013.05.016. Open manuscript.
  5. L. Bengtsson (1999). Dipole correction for surface supercell calculations. Physical Review B 59, 12301–12304. doi:10.1103/PhysRevB.59.12301.