AEGON
Atomic Environment for Global OptimizatioN — an open-source Python framework for the global optimization of atomic clusters and molecules.
AEGON is built natively on top of the Atomic Simulation Environment (ASE) and operates directly on ase.Atoms objects. It provides a self-contained toolkit covering every stage of a global optimization workflow, organized into three subpackages that mirror the three stages of the search: generation (random, symmetry-constrained, and genetic-algorithm-operator structure creation), optimization (local relaxation — built-in potentials and external QM/FF codes behind one plugin registry), and discrimination (structure deduplication). Performance-critical routines are accelerated through Numba just-in-time compilation.
Table of Contents
- Features
- Installation
- Dependencies
- Module Overview
- Usage
- Reference Databases
- Sutton-Chen Parameters
- Known Dead Code
- Citation
- Authors
- License
Features
- Random structure generation — nine structural templates (compact 3D, diffuse 3D, planar 2D, spherical shell, wire, ring, two-ring, helix, eye) with covalent-radii-based distance constraints and BFS connectivity verification.
- Symmetry-constrained generation — orbit-by-orbit placement for 30+ molecular point groups (C1 through Ih), with automatic fallback when the composition is incompatible with the requested symmetry.
- Periodic crystal generation — space-group-aware random crystal structures for all 230 space groups using ASE symmetry operations.
- Built-in potential energy calculators — Lennard-Jones (LJ) and Sutton-Chen (SC) potentials with Numba-accelerated energy and force evaluation; L-BFGS-B local minimization; ASE Effective Medium Theory (EMT) via BFGS; a Numba-accelerated periodic empirical engine (LJ + Buckingham + Ewald, cell+positions relaxed via
UnitCellFilter) for TiO2, MgAl2O4, MgSiO3, and SrTiO3; ANI machine-learned potentials (ANI1x/ANI1ccx/ANI2x, optional[ani]extra). - Calculator registry — a plugin-style registry (
aegon.optimization.build(calc_type, **kwargs)) that drives full parallel local optimizations for LJ, SC, TIO2, EMT, PERIODIC, ANI, GAUSSIAN, ORCA, MOPAC, GULP, and VASP behind one interface. A generic'ASE'entry dynamically wraps anyase.calculators.Calculatorby module + class name (optionally relaxing cell and positions together via anase.filterscell filter for periodic structures), so new ASE-compatible potentials work without new registry code. - Periodic-aware GULP/VASP —
GulpEngine/VaspEngineauto-detect already-periodic input (any(atoms.pbc)) and preserve the real cell instead of vacuum-boxing it viamolecule2poscar(which stays the default for non-periodic clusters), so the same registry entries serve both cluster codes (growpal) and crystal structure prediction (solids). - External quantum chemistry interfaces — per-code parsers under
aegon.parsing(libcode_gaussian/libcode_orca/libcode_mopac/libcode_gulp/libcode_vasp: geometry, trajectory, termination status), plus a unified convenience parser (aegon.parsing.read_out) for output files from Gaussian, ORCA, VASP, GULP, and MOPAC; input generation and batch execution with parallel queuing (libengine_gaussian/libengine_orca/libengine_mopac/libengine_gulp/libengine_vasp). - Layered site configuration —
aegon.configresolves installation-specific settings (binary paths, scratch folders) from an environment variable, an XDG user config file, or packaged defaults, validated with Pydantic — kept separate from per-run parameters. - Consistent unit system —
aegon.unitsties energy and force units together as one choice (eV/eV·Å⁻¹,atomic/Eh·bohr⁻¹, orkcal/kcal·mol⁻¹·Å⁻¹), applied uniformly by every calculator. - Genetic algorithm operators — mutation (atom displacement, twist), Deaven-Ho cut-and-splice crossover, dihedral rotamer exploration along bridge bonds, and fitness-proportional roulette wheel selection with a tanh-based fitness mapping.
- Structure discrimination — USR (Ultrafast Shape Recognition) descriptors for fast deduplication/filtering of cluster pools, and MBTR descriptor-based comparison for periodic crystal pools.
- Reference cluster databases — pre-optimized LJ clusters (5–130 atoms) and Sutton-Chen clusters for ten transition and main-group metals (Ag, Al, Au, Cu, Ir, Ni, Pb, Pd, Pt, Rh, up to 90 atoms), loaded lazily and cached per session.
- Visualization — inline Jupyter/Colab rendering with py3Dmol; support for periodic structures with unit-cell edges.
Installation
pip install aegon
Requires Python >= 3.10. To use the ANI machine-learned potentials (torch/torchani, a heavy optional dependency not needed for anything else in AEGON):
pip install aegon[ani]
Google Colab
!pip install aegon
Dependencies
| Package | Role |
|---|---|
| ASE | Atomic structure representation (Atoms objects) |
| NumPy | Array operations throughout |
| SciPy | L-BFGS-B optimization, k-d tree, sparse graph |
| Numba | JIT-compiled energy, force, and descriptor kernels |
| py3Dmol | Inline 3D visualization in Jupyter/Colab |
| Pydantic | Validation of layered site configuration (aegon.config) |
| PyYAML | Site configuration file format |
| joblib | Process-based parallelism for calculators (opt_LJ_parallel, opt_SC_parallel, opt_ASE_parallel (EMT included), ANI) |
| PyTorch / TorchANI | ANI machine-learned potentials — optional, pip install aegon[ani] |
MatterSim (pip install mattersim) is
not a dependency or extra of AEGON — AEGON's own source never imports it, it's
only used in examples/example_opt_crystal_mattersim.py through the generic
'ASE' strategy (optimization/potentials/ase_generic.py), which can wrap any
ASE-compatible calculator without AEGON code changes. Adding it as a formal
extra was deliberately rejected: MatterSim pulls in a large, unrelated
dependency tree (pymatgen, torch_geometric, phonopy/phono3py, wandb, the Azure
SDK, ...) that has nothing to do with AEGON's minimal core.
Known conflict if you install both aegon[ani] and mattersim in the same
environment: MatterSim requires torch>=2.2.0 with no upper bound, while
TorchANI 2.7.9 declares torch<=2.8,>=2.0. pip install mattersim will
happily upgrade torch past 2.8 to satisfy its own constraint, which pip check then reports as a broken requirement for torchani. In practice ANI
has been verified to still run correctly against torch==2.13.0 (installed by
MatterSim) — this is a stale declared ceiling in TorchANI's metadata, not an
observed runtime failure — but the two packages are not a clean, warning-free
combination, and there's no way to prevent this from aegon's pyproject.toml
since neither package is one of its extras.
Module Overview
AEGON's own code is organized into three subpackages that mirror the three stages of a global optimization search, plus shared infrastructure used across all three.
1. generation — creating structures
Three structure types (cluster, crystal, rotamer), each split the same way: a
_random module for stochastic generation and, where a GA drives the search,
matching _crossover/_mutant modules for its operators. Each pair shares
the same two public entry points: a single-pair primitive
(crossover(parent_a, parent_b, ...), kept as crossover_deavenho for
clusters since that names a specific published algorithm) and a
population-level driver for one GA generation (popgen_children/
popgen_mutants), identically named across all three structure types.
| Module | Description |
|---|---|
generation/cluster_random.py |
Random cluster generators (nine structural templates, parallel batch generation) and symmetry-constrained generators for 30+ point groups |
generation/cluster_crossover.py |
Deaven-Ho cut-and-splice crossover for clusters (crossover_deavenho, popgen_children) |
generation/cluster_mutant.py |
Mutation operators for clusters: atom displacement, twist, overlap resolution (popgen_mutants) |
generation/crystal_random.py |
Space-group-aware periodic crystal generator for all 230 space groups |
generation/crystal_crossover.py |
Cut-and-splice crossover for periodic crystals (crossover), used by solids |
generation/crystal_mutant.py |
Mutation operators for periodic crystals: lattice strain, atom exchange (popgen_mutants), used by solids |
generation/rotamer_random.py |
Stochastic rotamer generation: dihedral rotamer search along bridge bonds using the molecular graph (make_random_rotamers) |
generation/rotamer_crossover.py |
Crossover operator for rotamers (crossover, popgen_children) |
generation/rotamer_mutant.py |
Mutation operator for rotamers (popgen_mutants) |
generation/selection.py |
Roulette wheel selection with tanh-based fitness proportional to energy ranking — used internally by cluster_crossover.py/cluster_mutant.py's popgen_children/popgen_mutants, and standalone by GA drivers (glomos, solids) |
2. optimization — relaxing structures
| Module | Description |
|---|---|
optimization/registry.py |
Plugin registry (register_calculator, build, available) — every calculator strategy below registers here, so aegon.optimization.build(calc_type, **kwargs) drives all of them behind one interface |
optimization/potentials/lj.py |
Lennard-Jones energy, forces, and L-BFGS-B local minimization (Numba-accelerated) + 'LJ' strategy |
optimization/potentials/sc.py |
Sutton-Chen potential for 10 metals with parameters; Numba-accelerated energy/forces and opt_sc/opt_SC_parallel + 'SC' strategy |
optimization/potentials/tio2.py |
Buckingham-Coulomb-LJ potential for TiO2 clusters + 'TIO2' strategy |
optimization/potentials/emt.py |
'EMT' strategy: a thin ASECalculatorStrategy preset (position-only, BFGS, fmax=0.001, steps=200) for ASE's Effective Medium Theory potential — no separate implementation, reuses ase_generic.py's engine |
optimization/potentials/crystal_empirical.py |
Periodic empirical engine (LJ + Buckingham + Ewald, cell+positions relaxed via UnitCellFilter) with built-in PotentialSpecs for TiO2, MgAl2O4, MgSiO3, SrTiO3 + 'PERIODIC' strategy (spec='TIO2'/'MGAL2O4'/'MGSIO3'/'SRTIO3', or a custom PotentialSpec) |
optimization/potentials/ase_generic.py |
Dynamically wraps any ase.calculators.Calculator by module+class name + 'ASE' strategy |
optimization/potentials/ani.py + optimization/ani_backend.py |
ANI (ANI1x/ANI1ccx/ANI2x) machine-learned potential via torchani + 'ANI' strategy. Split into a thin, eagerly-imported strategy (alongside the other potentials) and a heavy backend imported lazily only when the strategy actually runs — deliberately kept outside potentials/, since unlike every file in there it must never be added to an eager __init__.py import, so import aegon.optimization never requires the optional [ani] extra |
optimization/external/<code>.py |
'GAUSSIAN'/'ORCA'/'MOPAC'/'GULP'/'VASP' strategies — thin adapters that delegate the actual work to aegon.parsing |
parsing/libcode_<code>.py |
Output parsing and geometry/trajectory extraction for each external code (gaussian, orca, mopac, gulp, vasp) |
parsing/libengine_<code>.py |
Input generation and batch execution for each external code (gaussian, orca, mopac, gulp, vasp) |
parsing/readouts.py |
read_out — unified dispatch (geo/traj) over parsing/* for Gaussian, ORCA, VASP, GULP, and MOPAC output files; re-exported as aegon.parsing.read_out |
3. discrimination — filtering redundant structures
| Module | Description |
|---|---|
discrimination/cluster_usr.py |
USR descriptor computation, batch deduplication (deduplicate_by_usr), and filtering against a reference pool — clusters/molecules |
discrimination/crystal_mbtr.py |
MBTR descriptor-based structure comparison and deduplication for periodic crystal pools (requires the optional dscribe dependency) |
Shared infrastructure
| Module | Description |
|---|---|
data/clusterdb.py |
aegondb class — unified dispatch (by model name) over pre-optimized LJ and SC reference clusters, delegating to data/lj.py/data/sc.py |
data/lj.py |
Direct access to LJ reference clusters via get_lj_cluster(N) |
data/sc.py |
Direct access to SC reference clusters via get_sc_cluster(N, symbol) |
io/poscar.py |
POSCAR/CONTCAR file reading and writing |
io/xyz.py |
Concatenated multi-structure XYZ I/O (readxyzs, writexyzs — plain or, via extended=True, ASE's extended XYZ with cell/PBC and optional forces) |
io/stdio.py |
Composition I/O: reading composition blocks from AEGON input files, cluster naming |
io/atoms2image.py |
Static structure rendering to image files, with unit-cell edges and optional force arrows |
io/gcolab.py |
Inline py3Dmol visualization for Jupyter and Google Colab (viewmol_ASE) |
geometry.py |
Distance, graph/connectivity, rotation, and alignment utilities on ase.Atoms (pure geometry, no I/O) |
population.py |
Bookkeeping over lists of ase.Atoms shared by all three blocks: labeling (rename), ranking (sort_by_energy), filtering (cutter_nonconnected, cutter_energy) |
units.py |
Paired energy/force unit conversion (energy_factor, force_factor, unit_labels) shared by every calculator |
queuing.py |
Parallel bash script execution via multiprocessing.Queue |
config/ |
Layered site configuration (env var → XDG user config → packaged defaults), validated with Pydantic; inspect with python -m aegon.config show |
Usage
Three complete examples below, one per subpackage from
Module Overview — this is the same generate →
optimize → discriminate sequence a GA driver (glomos, solids) repeats
every generation, shown here as three standalone steps.
1. Generating structures
generation/cluster_random.py covers both unconstrained and
symmetry-constrained cluster generation; generation/crystal_random.py and
generation/rotamer_random.py cover the other two structure types (periodic
crystals, single-molecule conformers — see Module Overview).
from aegon.generation.cluster_random import make_molecules_random, make_clusters_symmetric, make_cluster_symmetric
composition = ['Au'] * 13
# Unconstrained random generation, covalent-radii distance constraints + BFS
# connectivity check, generated in parallel
random_pop = make_molecules_random(composition, count=100, n_cores=4)
# Symmetry-constrained generation: each structure gets an automatically
# compatible point group
symmetric_pop = make_clusters_symmetric(composition, count=100, n_cores=4)
# Or fix a specific point group
mol_ih = make_cluster_symmetric(composition, point_group='Ih')
2. Optimizing structures
Every calculator — built-in potentials, ANI, or an external code — is driven
through the same registry entry point, aegon.optimization.build:
from aegon.optimization import build, available
print(available())
# ['ANI', 'ASE', 'EMT', 'GAUSSIAN', 'GULP', 'LJ', 'MOPAC', 'ORCA', 'PERIODIC', 'SC', 'TIO2', 'VASP']
calc = build('SC', metal_symbol='Au', units='eV')
optimized = calc.optimize_parallel(random_pop, n_jobs=4)
# Periodic empirical potentials (no external binary) work the same way
calc_periodic = build('PERIODIC', spec='TIO2', units='eV')
optimized_crystal = calc_periodic.optimize_parallel(crystal_population, n_jobs=4)
units ('eV'/'atomic'/'kcal') fixes energy and force together,
applied uniformly by every calculator via aegon.units.energy_factor/force_factor.
The potential-specific functions (opt_LJ_parallel, opt_sc/opt_SC_parallel,
...) underneath each 'LJ'/'SC'/... strategy are also directly importable
from optimization/potentials/*.py if you don't need the registry indirection.
External codes need binary paths and scratch folders, resolved from a layered site configuration (env var → XDG user config → packaged defaults, Pydantic-validated):
python -m aegon.config show
To read an already-finished calculation instead of running a new one:
from aegon.parsing import read_out
reader = read_out()
mol = reader.geo('gaussian', 'output.log') # final geometry
traj = reader.traj('orca', 'calculation.out') # full optimization trajectory
3. Discriminating structures
from aegon.population import sort_by_energy
from aegon.discrimination.cluster_usr import deduplicate_by_usr
ranked = sort_by_energy(optimized, opt=1)
unique = deduplicate_by_usr(ranked, tols=0.99, tole=0.1, mono=True)
print(f"{len(optimized)} → {len(unique)} unique structures")
for mol in unique[:5]:
print(mol.info['i'], mol.info['e'])
deduplicate_by_usr ranks by USR (Ultrafast Shape Recognition) descriptor
similarity within tole (eV) of each other; mono=True skips the descriptor's
moment-of-inertia component (irrelevant for single-element clusters). For
periodic crystal pools, discrimination/crystal_mbtr.py provides the same
deduplication via MBTR descriptors (requires the optional dscribe dependency).
Genetic algorithm operators
from aegon.generation.cluster_mutant import atom_displacement, twist_mutation
from aegon.generation.cluster_crossover import crossover_deavenho
from aegon.generation.selection import get_roulette_wheel_selection
# Select parents by roulette wheel (fitness-proportional)
parents = get_roulette_wheel_selection(optimized, nmating=20)
# Mutation
mutant = atom_displacement(parents[0], delta=0.4)
# Deaven-Ho cut-and-splice crossover
atomlist = parents[0].get_chemical_symbols()
children = crossover_deavenho(parents[0], parents[1], atomlist)
Writing structures back out is a property of the ase.Atoms object itself
(periodic or not, with or without forces), not of which code produced it:
aegon.io.xyz.writexyzs (plain or, with extended=True, ASE's extended XYZ
format) or aegon.io.poscar.writeposcars.
Visualize in Jupyter / Colab
from aegon.io.gcolab import viewmol_ASE
viewmol_ASE(mol, width=500, height=500)
Reference Databases
AEGON ships two bundled databases loaded lazily at runtime. Each entry is returned as an ase.Atoms object.
| Database | Potential | Available elements | Sizes |
|---|---|---|---|
LJ_clusters_data.npz |
Lennard-Jones (ε = 1 eV, r₀ = 2^(1/6) σ = 3 Å) | any (Mo by default) | N = 5–130 |
SC_<El>_clusters_data.npz |
Sutton-Chen | Ag, Al, Au, Cu, Ir, Ni, Pb, Pd, Pt, Rh | N = 5–90 |
These datasets were generated with the GrowPAL diversity-preserving algorithm and validated against the Wales reference database (LJ) and literature results (SC).
Access via direct functions
from aegon.data.lj import get_lj_cluster
from aegon.data.sc import get_sc_cluster
# LJ cluster: info keys are 'i' (ID string) and 'e' (energy in eV)
lj38 = get_lj_cluster(38)
print(lj38.info['i'], lj38.info['e'])
# SC cluster
au20 = get_sc_cluster(20, symbol='Au')
print(au20.info['i'], au20.info['e'])
Access via aegondb
from aegon.data.clusterdb import aegondb
# LJ cluster: info keys are 'i' (ID string) and 'e' (energy in eV) — same
# convention as the direct functions above, since aegondb delegates to them
lj38 = aegondb.get(N=38, model='LJ')
print(lj38.info['i'], lj38.info['e'])
# SC cluster
au20 = aegondb.get(N=20, model='SC', element='Au')
# List available sizes
print(aegondb.list_available(model='SC', element='Pt'))
Compare Sutton-Chen energies between two metals
import numpy as np
from aegon.optimization.potentials.sc import SUTTON_CHEN_PARAMS
from aegon.data.sc import get_sc_cluster
metal_type1, metal_type2 = 'Pt', 'Au'
epsilon1 = SUTTON_CHEN_PARAMS[metal_type1]['epsilon']
epsilon2 = SUTTON_CHEN_PARAMS[metal_type2]['epsilon']
for i in range(4, 90 + 1):
atoms1 = get_sc_cluster(i, symbol=metal_type1)
atoms2 = get_sc_cluster(i, symbol=metal_type2)
e1 = atoms1.info['e'] / epsilon1
e2 = atoms2.info['e'] / epsilon2
deltae = np.abs(e1 - e2)
print("%9s vs. %9s dE=%f" % (atoms1.info['i'], atoms2.info['i'], deltae))
Sutton-Chen Parameters
AEGON includes the original Sutton-Chen parameters from Sutton & Chen, Philos. Mag. Lett. 1990, 61, 139–146, for ten metals:
| Element | n | m | ε (eV) | a (Å) | C |
|---|---|---|---|---|---|
| Ni | 9 | 6 | 1.5707×10⁻² | 3.52 | 39.432 |
| Cu | 9 | 6 | 1.2382×10⁻² | 3.61 | 39.432 |
| Rh | 12 | 6 | 4.9371×10⁻³ | 3.80 | 144.41 |
| Pd | 12 | 7 | 4.1790×10⁻³ | 3.89 | 108.27 |
| Ag | 12 | 6 | 2.5415×10⁻³ | 4.09 | 144.41 |
| Ir | 14 | 6 | 2.4489×10⁻³ | 3.84 | 334.94 |
| Pt | 10 | 8 | 1.9833×10⁻² | 3.92 | 34.408 |
| Au | 10 | 8 | 1.2793×10⁻² | 4.08 | 34.008 |
| Pb | 10 | 7 | 5.5765×10⁻³ | 4.95 | 45.778 |
| Al | 7 | 6 | 3.3147×10⁻² | 4.05 | 16.339 |
from aegon.optimization.potentials.sc import SUTTON_CHEN_PARAMS
params = SUTTON_CHEN_PARAMS['Pd']
print(params['n'], params['m'], params['epsilon'])
Known Dead Code
Functions currently unreferenced anywhere in the codebase, flagged here so they are easy to find:
| Function | Location | Why it's dead |
|---|---|---|
get_best_geometry_vasp |
parsing/libcode_vasp.py |
Never called. get_geometry_vasp already scans the entire OUTCAR ionic-step trajectory (via get_traj_vasp) and returns the lowest-energy structure regardless of convergence — the same "best available" behavior get_best_geometry_gaussian/get_best_geometry_orca provide for those codes, just unified into one function instead of two. libengine_vasp.py's retry/rescue logic calls get_geometry_vasp directly and never needed the separate _best_ variant. |
display_info(moleculein, stage_string, dicc_term) (3-argument form) |
parsing/libcode_gulp.py |
Never called; superseded by GulpEngine's own print statements in libengine_gulp.py. Note growpal.libgrowpal has its own unrelated 2-argument display_info — same name, different function, don't confuse the two. |
tag — removed, was io/poscar.py |
Never called anywhere in the codebase. Tagged atoms by atomic-number groups without reordering them; superseded in every real use case by order_and_tag, which does the same tagging plus the reordering POSCAR output actually needs. |
Citation
If you use AEGON in your research, please cite the associated manuscript (in preparation).
AEGON is the optimization backend used in:
Gutiérrez-Campos I., Merino G., Ortiz-Chi F. Morphological Diversity as a Selection Principle in Growth-Based Global Optimization.
López-Castro C., Ortiz-Chi F., Merino G. An Efficient Growth Pattern Algorithm (GrowPAL) for Cluster Structure Prediction. J. Chem. Theory Comput. 2024, 20, 4939–4948.
Authors
- Filiberto Ortiz-Chi — Secihti-Departamento de Física Aplicada, Cinvestav-IPN, Mérida, México
- Aileen Garcia Cano — Facultad de Ingeniería, Universidad Autónoma de Yucatán, Mérida, México
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aegon-1.3.9.tar.gz.
File metadata
- Download URL: aegon-1.3.9.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b592dc108798fa116025fd9d84bcd8b7d957dfde097eb6b0081c90b13a48566f
|
|
| MD5 |
80d7d12558df1c4db067c13cea7a2ffc
|
|
| BLAKE2b-256 |
2a764e3dc2d99d63c58cbb5dcac79800493c9a67a7a8cb85fb96d602f80aaf84
|
File details
Details for the file aegon-1.3.9-py3-none-any.whl.
File metadata
- Download URL: aegon-1.3.9-py3-none-any.whl
- Upload date:
- Size: 1.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
191323d80c22609e8ce34d6f215158257a02c6bfba60ec7fb28cef4884545b4f
|
|
| MD5 |
cd987ba7cd0bdfea41641f2a899af541
|
|
| BLAKE2b-256 |
e43a185c39369d3ed85e50f6db736e5d7d1eab0c2b385d362bcb9378fb227daa
|