Metadata-Version: 2.4
Name: glomos
Version: 0.3.1
Summary: GLobal Optimization of MOlecular Systems
Author-email: Filiberto Ortiz Chi <fortiz666@gmail.com>, Aileen Garcia Cano <garciacanoaileen@gmail.com>, Gabriel Merino <gabriel.merino2@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/fortizchi/glomos
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: aegon[ani]>=1.3.9
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# GLOMOS

**GLobal Optimization of MOlecular Systems — a genetic algorithm for the global optimization of atomic clusters and molecules, built on top of [AEGON](https://pypi.org/project/aegon/).**

GLOMOS orchestrates the genetic algorithm (initial population, crossover, mutation, fitness-proportional selection, structural deduplication, stop criteria) and delegates every energy evaluation and local optimization to AEGON's calculator registry. GLOMOS itself never talks to a quantum chemistry code or a potential directly — it only calls `aegon.calculators.build(calc_type, **kwargs)`, so any calculator AEGON supports is automatically available to the genetic algorithm.

---

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Dependencies](#dependencies)
- [The INPUT file](#the-input-file)
- [Supported calculators](#supported-calculators)
- [Stochastic kick search](#stochastic-kick-search)
- [Genetic algorithm search](#genetic-algorithm-search)
- [Rotamer / conformer search](#rotamer--conformer-search)
- [Citation](#citation)
- [Authors](#authors)
- [License](#license)

---

## Features

- **Three search drivers** — `heuristic_kick.py` (staged local-opt + discrimination, no evolutionary operators), `heuristic_ga.py` (roulette-wheel GA over clusters/crystals), `heuristic_ga_rotamers.py` (GA over dihedral angles for conformer search).
- **Calculator-agnostic** — every driver dispatches through AEGON's registry: LJ, Sutton-Chen, TiO2, EMT, ANI, Gaussian, ORCA, MOPAC, GULP, VASP, selected by a single `calculator` key.
- **Unit-consistent** — one `units` key (`eV`/`atomic`/`kcal`) fixes energy and force together across every calculator.
- **Plain-text input files** — `INPUT_GLOMOS_<CALCULATOR>_<ALGORITHM>_<SYSTEM>.txt` (`GEGA`/`KICK`/`RTMR`), same convention as `solids/examples`.

---

## Installation

```bash
pip install glomos
```

Requires Python >= 3.10. GLOMOS depends on AEGON with the `[ani]` extra (installs `torch`/`torchani` for the ANI calculator); no separate installation step is needed.

---

## Dependencies

| Package | Role |
|---|---|
| [aegon](https://pypi.org/project/aegon/) `[ani]` | Structure generation, GA operators, unit conversion, and the calculator registry (LJ, SC, TiO2, EMT, ANI, Gaussian, ORCA, MOPAC, GULP, VASP) |

All other dependencies (ASE, NumPy, SciPy, Numba, Pydantic, PyYAML, joblib, torch, torchani) come transitively through `aegon[ani]`.

---

## The INPUT file

GLOMOS reads a plain-text input file with a composition block and key-value
parameters (parsed by `aegon.libstdio.read_main_input`):

```
---COMPOSITION---
H  4
O  2
---COMPOSITION---

#EVOLUTIVE PARAMETERS:
nof_initpop             4    #Initial Population
nof_matings             2    #Number of matings
nof_mutants             2    #Number of mutants

#ENERGY UNITS: eV | atomic (Eh) | kcal (kcal/mol)
units                   kcal   #sets energy AND force units together

#DISCRIMINATION PARAMETERS:
tol_similarity          0.96
tol_energy              0.10
cutoff_energy           10.0
cutoff_population       10

#STOP CRITERION:
nof_generations         10
nof_repeats             3
nof_stagnant            5

#THEORY LEVEL:
calculator              GAUSSIAN
nof_processes           4

#OUTPUT FILE:
initial_file            initial.xyz
output_file             summary.xyz
```

Calculator-specific keys (`metal_symbol` for SC, `ani_model` for ANI,
`vasp_potcar`/`vasp_latsp` for VASP, the `---GAUSSIAN---`/`---ORCA---`/
`---MOPAC---`/`---GULP---`/`---VASP---` route blocks) apply only to the
calculator selected. Binary paths and scratch folders come from AEGON's site
configuration (`python -m aegon.config show`), not from this file.

Every run prints a warning for any key or block present in the INPUT file but
never actually read by the algorithm/calculator combination selected — e.g. a
typo, a key that only applies to a different calculator, or a stop-criterion
key from `KICK` left over after switching an INPUT file to `GEGA`. Silent
otherwise.

---

## Supported calculators

| `calculator` | Backend | Native units | KICK | GEGA | RTMR | Notes |
|---|---|---|:---:|:---:|:---:|---|
| `LJ` | `aegon.libcalc_lj` | eV | ✅ | ✅ | — | Generic Lennard-Jones, no external binary |
| `SC` | `aegon.libcalc_sc` | eV | ✅ | ✅ | — | Sutton-Chen; requires `metal_symbol` |
| `TIO2` | `aegon.libcalc_tio2` | eV | ✅ | ✅ | — | Buckingham + Coulomb + LJ for TiO2 |
| `EMT` | `aegon.libcalc_emt` | eV | ✅ | ✅ | — | ASE Effective Medium Theory; Al, Ni, Cu, Pd, Ag, Pt, Au |
| `ANI` | `aegon.libcalc_ani` | kcal/mol | ✅ | ✅ | ✅ | Machine-learned potential (ANI1x/ANI1ccx/ANI2x); requires `aegon[ani]` |
| `GAUSSIAN` | Gaussian 16 | kcal/mol | ✅ | ✅ | ✅ | External binary |
| `ORCA` | ORCA | kcal/mol | ✅ | ✅ | ✅ | External binary |
| `MOPAC` | MOPAC | kcal/mol | ✅ | ✅ | ✅ | External binary |
| `GULP` | GULP | eV | ✅ | ✅ | — | External binary; periodic and cluster-in-vacuum-box |
| `VASP` | VASP | kcal/mol | ✅ | ✅ | — | External binary; periodic, requires POTCAR |

`RTMR` is limited to `ANI`/`GAUSSIAN`/`ORCA`/`MOPAC` — the rest have no
organic-molecule parameterization or are otherwise not the tool for a
conformer search.

---

## Stochastic kick search

`heuristic_kick.py`: a population goes through `number_of_stages` local-opt +
discrimination passes, no crossover/mutation. Template-driven engines
(Gaussian, ORCA, MOPAC, GULP, VASP) take one input block per stage
(`---GULP1---`/`---GULP2---`, `---INCAR1---`/`---KPOINTS1---` for VASP), so
stages can run at different levels of theory.

```python
from glomos.heuristic_kick import stochastic_kick

population = stochastic_kick('INPUT_GLOMOS_LJ_KICK_Mo8.txt')
```

Examples: `x_run_glomos_{lj,sc,tio2,emt}_kick_{mo8,cu8,tio2,au8}.py`,
`..._gulp_kick_cu8.py`, `..._{ani,orca,gaussian,vasp}_kick_h2o.py` (seeded
from the matching GEGA run's `summary.xyz`), `..._mopac_kick_si5o6.py`
(MNDO, self-generated population — see [Genetic algorithm search](#genetic-algorithm-search)),
and `..._gaussian_kick_b10.py` (multi-stage boron refinement).

---

## Genetic algorithm search

`heuristic_ga.py`: roulette-wheel crossover/mutation, energy-cutoff + USR
deduplication, stop on max generations / repeated isomers / stagnant cycles.

```python
from glomos.heuristic_ga import genetic_algorithm

population = genetic_algorithm('INPUT_GLOMOS_GAUSSIAN_GEGA_H2O.txt')
for mol in population[:5]:
    print(mol.info['i'], mol.info['e'], mol.info['c'])
```

Population is written to `output_file` after every generation. Examples:
`x_run_glomos_{lj,sc,tio2,emt}_gega_{mo8,cu8,tio2,au8}.py`,
`..._gulp_gega_cu8.py`, `..._{ani,orca,gaussian,vasp}_gega_h2o.py`,
`..._mopac_gega_si5o10.py` (MNDO).

`nof_opt_attempts` (default 1, same key and semantics as `KICK` above) retries
any structure whose `info['c']` isn't 1 — i.e. the calculator's job didn't
reach a real stationary point — from its current geometry, up to that many
total attempts, before it's allowed into fitness-proportional selection.
Applies to both the initial population and every generation's crossovers/
mutants, and works the same way for every calculator in the registry (not
just the external QM codes): `info['c']` is set uniformly by every
`*CalculatorStrategy.optimize_parallel()`, so the retry loop only depends on
that, never on which calculator produced it.

### Running several searches in sequence

```python
from glomos.heuristic_ga import genetic_algorithm

genetic_algorithm('INPUT_GLOMOS_LJ_GEGA_Mo8.txt')
genetic_algorithm('INPUT_GLOMOS_SC_GEGA_Cu8.txt')
genetic_algorithm('INPUT_GLOMOS_GAUSSIAN_GEGA_H2O.txt')
```

---

## Rotamer / conformer search

`heuristic_ga_rotamers.py`: a GA over dihedral angles of a single molecule.
Rotatable bonds are identified from the molecular graph of a `rotamer_seed`
XYZ file; no `COMPOSITION` block.

```python
from glomos.heuristic_ga_rotamers import conformational

population = conformational('INPUT_ROTAMERS.txt')
```

`calculator` is `ANI` (`ani_model` selects `ANI1x`/`ANI1ccx`/`ANI2x`), `MOPAC`,
`GAUSSIAN`, or `ORCA`.

- `examples/INPUT_GLOMOS_MOPAC_RTMR_C8H9NO2.txt` / `..._ANI_RTMR_C8H9NO2.txt`
  — paracetamol, `ANI1ccx`.
- `examples/INPUT_GLOMOS_GAUSSIAN_RTMR_C2H6O.txt` / `..._ORCA_RTMR_C2H6O.txt`
  — ethanol, PBE0/Def2SVP.

---

## Citation

If you use GLOMOS in your research, please cite the associated manuscript (in preparation), and the AEGON backend it builds on:

> 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

- **Aileen Garcia Cano** — Facultad de Ingeniería, Universidad Autónoma de Yucatán, Mérida, México
- **Gabriel Merino** — Departamento de Física Aplicada, Cinvestav-IPN, Mérida, México
- **Filiberto Ortiz-Chi** — Secihti-Departamento de Física Aplicada, Cinvestav-IPN, Mérida, México

---

## License

See [LICENSE](LICENSE).
