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
Generate and optimize a random cluster
from aegon.generation.cluster_random import make_molecules_random
from aegon.optimization.potentials.lj import opt_LJ_parallel
composition = ['Au'] * 7
# Generate 100 random starting structures in parallel
population = make_molecules_random(composition, count=100, n_cores=4)
# Parallel local minimization with the Lennard-Jones potential
optimized = opt_LJ_parallel(population, n_jobs=4)
Generate symmetry-constrained clusters
from aegon.generation.cluster_random import make_clusters_symmetric, make_cluster_symmetric
# Generate 50 clusters with automatically compatible point groups
population = make_clusters_symmetric(['Au'] * 13, count=50, n_cores=4)
# Or fix a specific point group
mol = make_cluster_symmetric(['Au'] * 13, point_group='Ih')
Optimize with the Sutton-Chen potential
from aegon.generation.cluster_random import make_molecules_random
from aegon.optimization.potentials.sc import opt_sc, opt_SC_parallel
composition = ['Au'] * 10
population = make_molecules_random(composition, count=50)
# Single structure
optimized_one = opt_sc(population[0], metal_type='Au')
# Parallel batch
optimized_all = opt_SC_parallel(population, metal_type='Au', n_jobs=4)
Deduplicate a structure pool with USR
from aegon.discrimination.cluster_usr import deduplicate_by_usr
unique = deduplicate_by_usr(optimized, tols=0.99, tole=0.1, mono=True)
print(f"{len(optimized)} → {len(unique)} unique structures")
Apply 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)
Read output from quantum chemistry codes
from aegon.parsing import read_out
reader = read_out()
# Final optimized geometry (supported: 'gaussian', 'orca', 'vasp', 'gulp', 'mopac')
mol = reader.geo('gaussian', 'output.log')
# Full optimization trajectory (supported: 'gaussian', 'orca', 'vasp')
traj = reader.traj('orca', 'calculation.out')
read_out is a convenience wrapper for reading already-finished calculations.
To write the resulting structures back out, use aegon.io.xyz.writexyzs
(plain or, with extended=True, ASE's extended XYZ format) or
aegon.io.poscar.writeposcars — writing is a property of the ase.Atoms
object itself (periodic or not, with or without forces), not of which code
produced it, so it lives with the other general-purpose I/O utilities rather
than with the per-code parsers. To actually run a full parallel local
optimization with any supported code or potential — including external
binaries — use the calculator registry instead (see below).
Run a full optimization through the calculator registry
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(population, 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)
Every calculator shares the same units convention: choosing 'eV', 'atomic',
or 'kcal' fixes energy and force together (never mix units), applied
uniformly by aegon.units.energy_factor/force_factor.
Site configuration
Binary paths and scratch folders for external codes (Gaussian, ORCA, MOPAC, GULP, VASP) are resolved from a layered site configuration, separate from per-run parameters:
python -m aegon.config show
resolves (in order) $AEGON_CONFIG, $XDG_CONFIG_HOME/aegon/config.yaml (or
~/.config/aegon/config.yaml), then the packaged defaults — validated with
Pydantic (aegon.config.schemas).
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'))
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.7.tar.gz.
File metadata
- Download URL: aegon-1.3.7.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 |
418e735b986ef16ed2ea3b79b625b81a77c90e30eef4f54995bd0bf23091d041
|
|
| MD5 |
9174f41d6e41119856650a489b1cf00b
|
|
| BLAKE2b-256 |
7c309a28430a9436c2cdaa4b33f541b16c20ecf5a498dd841cc4414d5cb8771f
|
File details
Details for the file aegon-1.3.7-py3-none-any.whl.
File metadata
- Download URL: aegon-1.3.7-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 |
902d483f24bb9072008760337580d194415e1c2ffeff3cdf7dc1124b6afa2f31
|
|
| MD5 |
7dd85b828f9d500961185f0dd100913e
|
|
| BLAKE2b-256 |
27237530e919a884e5e71333a2f0d31be09801c961105c45766aad06d108a537
|