Geometries#

The Geometry model and the automol.geom module are the core of automol: almost everything else (identities, visualization, RDKit interoperability) is built on top of Geometry.

Creating a Geometry#

A Geometry is a pydantic model with four fields: atomic symbols, Cartesian coordinates (in Angstroms), charge, and spin (number of unpaired electrons, i.e. 2S):

from automol import Geometry

water = Geometry(
    symbols=["O", "H", "H"],
    coordinates=[[0.0, 0.0, 0.0], [0.0, 0.0, 0.96], [0.93, 0.0, -0.24]],
    charge=0,
    spin=0,
)

coordinates must have shape (len(symbols), 3) — a mismatch raises a ValueError at construction time, since this is standard pydantic field validation.

Per-atom properties#

Geometry exposes several derived, per-atom properties, backed by automol.utils.element’s periodic table data:

water.atom_count       # 3
water.masses           # isotopic masses, e.g. [15.9949, 1.0078, 1.0078]
water.atomic_numbers   # [8, 1, 1]
water.covalent_radii   # Pyykko covalent radii, in Angstroms
water.valences          # number of valence electrons per atom

Reading and writing xyz#

Geometry round-trips through the standard xyz format, both as instance methods and as module-level functions in automol.geom:

from automol import geom

xyz = water.xyz_block(comment="water")
water_rt = Geometry.from_xyz_block(xyz, charge=0, spin=0)

water.xyz_file(path="water.xyz")
water_rt = Geometry.from_xyz_file("water.xyz", charge=0, spin=0)

# equivalent module-level functions
xyz = geom.xyz_block(water, comment="water")
water_rt = geom.from_xyz_block(xyz, charge=0, spin=0)

charge and spin aren’t part of the xyz format, so they must be supplied explicitly when reading. A malformed or empty xyz block raises automol.utils.exc.XYZFormatError.

Molecular formula#

geom.hill_formula(water)  # "H2O"

Elements are ordered with carbon first, then hydrogen, then the rest alphabetically (Hill order) — the standard convention regardless of whether carbon is present.

Geometric properties#

automol.geom also exposes a handful of properties computed directly from coordinates:

geom.center_of_mass(water)     # mass-weighted centroid
geom.distance_matrix(water)    # pairwise atom-atom distances
geom.adjacency_matrix(water)   # binary connectivity, from covalent radii
geom.distance_keys(water)      # sorted (z1, z2, distance) descriptor

adjacency_matrix draws an edge between two atoms when their distance is less than sigma times the sum of their covalent radii (sigma=1.3 by default). distance_keys produces an order-independent geometric fingerprint useful for comparing or hashing geometries.

Transformations#

geom.transform provides rigid transformations that return a new Geometry by default, or mutate in place with in_place=True:

from scipy.spatial.transform import Rotation

shifted = geom.transform.translate(water, [1.0, 0.0, 0.0])
rotated = geom.transform.rotate(water, Rotation.from_euler("z", 90, degrees=True))
mirrored = geom.transform.reflect(water, normal=[0, 0, 1])

All three accept a keys argument to restrict the transformation to a subset of atoms by index, leaving the rest untouched:

geom.transform.translate(water, [1.0, 0.0, 0.0], keys=[0])  # move only atom 0

Next steps#