Metadata-Version: 2.4
Name: molsympy
Version: 0.1.5
Summary: Molecular symmetry detection and symmetrization
Author-email: Sebastian Hernandez-Gutierrez <s3b4s7i4nhg@gmail.com>, Diego Roman-Montalvo <romanmdiego@gmail.com>, Gabriel Merino <gabriel.merino2@gmail.com>, Filiberto Ortiz-Chi <fortiz666@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/hyl-kibou/molsympy
Classifier: Programming Language :: Python :: 3
Classifier: Intended Audience :: Science/Research
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: numba>=0.61.0
Requires-Dist: ase>=3.22
Provides-Extra: docs
Requires-Dist: mkdocs; extra == "docs"
Requires-Dist: mkdocs-material; extra == "docs"
Requires-Dist: mkdocstrings[python]; extra == "docs"
Requires-Dist: mkdocs-glightbox; extra == "docs"
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# MolSymPy

![Python](https://img.shields.io/badge/python-3.10+-blue)
![License](https://img.shields.io/badge/license-MIT-green)
![PyPI](https://img.shields.io/pypi/v/molsympy)

**MolSymPy** is an open-source Python package for molecular symmetry analysis in atomistic simulations. It is built natively on top of the [Atomic Simulation Environment (ASE)](https://wiki.fysik.dtu.dk/ase/) and operates directly on `ase.Atoms` objects, enabling seamless integration with atomistic simulation workflows.

## Features

- **Geometric idealization** — project nearly-symmetric structures onto their exact symmetry elements and orient the molecular frame by aligning principal and secondary symmetry axes with the Cartesian coordinate system.
- **Point group detection** — identify molecular point groups in Schoenflies notation, including the two infinite-order linear groups (C∞v and D∞h).
- **Symmetry-inequivalent atoms** — determine symmetry-inequivalent atoms using a path-compressed union-find algorithm operating on the complete symmetry permutation map.
- **Reference database** — companion collection of molecular and atomic-cluster geometries spanning the principal point groups, available in both raw and idealized forms.

Performance-critical routines are accelerated through [Numba](https://numba.readthedocs.io/) just-in-time compilation, providing efficient execution with no compilation requirements at install time.

## Installation

```bash
pip install molsympy
```

**Requirements:** Python ≥ 3.10, NumPy ≥ 1.24, Numba ≥ 0.61, ASE ≥ 3.22.

## Quick start

### Point group detection

```python
from ase.build import molecule
from molsympy import get_point_group

cyclopropane = molecule('C3H6_D3h')
print(get_point_group(cyclopropane)) #D3h
```

### Symmetry-inequivalent atoms

```python
from molsympy.collections import symmetrized
from molsympy import get_inequivalent

mol = symmetrized['C3h_1']
unique, parent = get_inequivalent(mol, geom_tol=0.05, eigen_tol=0.01)
print(unique)    # [0, 1, 2, 9, 10]
print(parent)    # [0, 1, 2, 1, 0, 2, 1, 0, 2, 9, 10, 9, 10, 9, 10]
```

### Symmetrization

```python
from molsympy.collections import unsymmetrized
from molsympy import symmetrize

atoms_U = unsymmetrized['C0v_1']     # unsymmetrized ase.Atoms
print(atoms_U.positions)             # [[-1.332400e-02  1.132466e+00  8.276000e-03]
                                     #  [ 2.311000e-03 -1.915900e-02  1.929000e-03]
                                     #  [-2.780300e-02  2.198949e+00  1.415400e-02]]
atoms_S = symmetrize(atoms_U)        # symmetrize ase.Atoms
print(atoms_S.positions)             # [[ 0.          0.         -0.55714544]
                                     #  [ 0.          0.          0.59460318]
                                     #  [ 0.          0.         -1.62374292]]
```

### Symmetry candidates (subgroup fan-out)

```python
from ase.build import molecule
from molsympy import generate_symmetry_candidates

benzene = molecule('C6H6')                    # D6h
for s in generate_symmetry_candidates(benzene):
    # Access Atom object with s.mol
    print(s.pg, s.rmsd)                       # D6h 1.6032259480710427e-07, D3h 1.4451283412026997e-07, ...
```

## API reference

### `get_point_group(mol, geom_tol=0.05, eigen_tol=None) → str`

Determine the point group of a molecule.

| Parameter | Type | Description |
|-----------|------|-------------|
| `mol` | `ase.Atoms` | Input molecule. |
| `geom_tol` | `float` | Geometric tolerance in Å (default `0.05`). |
| `eigen_tol` | `float \| None` | Relative tolerance for moment-of-inertia eigenvalues. Estimated automatically when `None`. |

Returns the Schoenflies symbol as a string (e.g. `"C2v"`, `"D3h"`, `"Oh"`).

---

### `symmetrize(mol, geom_tol=0.05, eigen_tol=None) → ase.Atoms`

Project a nearly-symmetric structure onto exact point-group symmetry.

Each set of symmetry-equivalent atoms (SEA) is handled by projecting a representative atom onto the symmetry element that fixes it, then mapping the remaining SEA members via the stored matrix representation of the connecting symmetry operation.

---

### `get_inequivalent(mol, geom_tol=0.3, eigen_tol=None) → (np.ndarray, np.ndarray)`

Find symmetry-inequivalent atoms.

Returns `(unique, parent)` where `unique` contains one representative index per equivalence class and `parent[i]` is the representative of atom `i`.

---

### `is_planar(mol, geom_tol=0.05) → bool`

Check whether all atoms lie in a common plane.

---

### `generate_symmetry_candidates(mol, geom_tol=0.05, eigen_tol=None, sort_by=0) → list[SymmetryResult]`

Generate symmetry-consistent geometries for all subgroups compatible with the detected point group.

Each `SymmetryResult` contains:
- `mol` — the symmetrized `ase.Atoms` object
- `pg` — the Schoenflies symbol
- `rmsd` — RMSD (Å) between original and symmetrized structure

`sort_by=0` sorts by group size (descending) then RMSD (ascending); `sort_by=1` sorts by RMSD first.

## Reference database

MolSymPy ships a companion database of molecular and atomic-cluster geometries indexed by point group:

```python
from molsympy.collections import symmetrized, unsymmetrized

# Lists of molecule IDs
print(unsymmetrized.names)         #['C0v_1', 'C0v_2', …, 'Td_3']
print(symmetrized.names)           #['C0v_1', 'C0v_2', …, 'Td_3']
# Equivalent lists asking for molecular formulas (alphabetical order):
print(unsymmetrized.formulas)      # ['AgC68N4H76O4', 'AuC18P2N6H24', …, 'ZrSi7C24H52']
print(symmetrized.formulas)        # ['AgC68N4H76O4', 'AuC18P2N6H24', …, 'ZrSi7C24H52']
# ASE Atoms objects can be called from their molecule IDs or molecular formulas:
mol1 = symmetrized['C3h_1']
mol2 = symmetrized['C6H6O3']
```

The two collections are:

| Object | Content |
|--------|---------|
| `symmetrized` | Idealized geometries with exact point-group symmetry |
| `unsymmetrized` | Raw geometries with slight numerical distortions |

### Lookup by molecular formula

Every structure in the database can also be retrieved by its molecular formula.
The key and the formula are interchangeable in all collection operations:

```python
from molsympy.collections import symmetrized, unsymmetrized

# These two calls return the same structure
atoms = unsymmetrized['C0v_1']
atoms = unsymmetrized['CNH']     # equivalent

# Works with both collections
mol_u = unsymmetrized['H2O']     # same as unsymmetrized['C2v_1']
mol_s = symmetrized['H2O']       # same as symmetrized['C2v_1']

# List all available formulas
print(unsymmetrized.formulas)    # ['AgC68N4H76O4', 'AuC18P2N6H24', …, 'ZrSi7C24H52']
```

The formula stored for each entry is the one embedded in the ``.npz`` database.
Each structure carries exactly one formula alias; looking up by key always works
regardless of whether a formula is defined.

## Examples

The [`examples/`](https://github.com/Hyl-Kibou/MolSymPy/tree/minimal/examples) directory contains standalone, runnable scripts for each feature shown above:

| Script | Description |
|--------|-------------|
| [`1_get_point_group.py`](https://github.com/Hyl-Kibou/MolSymPy/blob/minimal/examples/1_get_point_group.py) | Detect the point group of a molecule. |
| [`2_get_inequivalent.py`](https://github.com/Hyl-Kibou/MolSymPy/blob/minimal/examples/2_get_inequivalent.py) | Find symmetry-inequivalent atoms. |
| [`3_symmetrize.py`](https://github.com/Hyl-Kibou/MolSymPy/blob/minimal/examples/3_symmetrize.py) | Symmetrize a distorted structure. |
| [`4_generate_symmetry_candidates.py`](https://github.com/Hyl-Kibou/MolSymPy/blob/minimal/examples/4_generate_symmetry_candidates.py) | Generate symmetry candidates for all compatible subgroups. |
| [`database_example.py`](https://github.com/Hyl-Kibou/MolSymPy/blob/minimal/examples/database_example.py) | Access the reference database by key or molecular formula. |

## License

MIT — see [LICENSE](https://github.com/Hyl-Kibou/MolSymPy/blob/minimal/LICENSE).

## Authors

- Sebastian Hernandez-Gutierrez — Departamento de Física Aplicada, Cinvestav-IPN, Mérida, México
- Diego Roman-Montalvo — Departamento de Física Aplicada, Cinvestav-IPN, 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

If you use MolSymPy in your research, please cite the associated manuscript
