Metadata-Version: 2.4
Name: pyscal3
Version: 4.1.0
Summary: Python library written in C++ for calculation of local atomic structural environment
Author-email: Sarath Menon <sarath.menon@pyscal.org>
License: BSD-3-Clause
Project-URL: Homepage, https://pyscal.org
Project-URL: Documentation, https://pyscal.org
Project-URL: Repository, https://github.com/pyscal/pyscal3
Project-URL: Issues, https://github.com/pyscal/pyscal3/issues
Project-URL: Changelog, https://github.com/pyscal/pyscal3/releases
Keywords: atomic structure,steinhardt,descriptors,molecular dynamics,materials science
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: C++
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Topic :: Scientific/Engineering :: Chemistry
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: scipy>=1.15
Requires-Dist: ase
Requires-Dist: pyyaml
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Dynamic: license-file

# pyscal: python Structural Environment Calculator

Complete documentation with examples available [here](https://pyscal.org/).

## What changed in version 4

pyscal grew over the years from a small wrapper around a few C++ routines into a full structural-analysis toolkit. With each addition the original `System` / `Atoms` object model became more rigid: every new descriptor had to be threaded through the same class hierarchy, neighbor lists were tied to a particular `System` instance, and interoperating with the rest of the atomistic-simulation Python ecosystem (ASE, pymatgen, OVITO, LAMMPS dump readers) required converting back and forth between formats.

Version 4 is a ground-up rewrite around four changes:

- **ASE `Atoms` is the data structure.** pyscal no longer ships its own atoms class. Any `ase.Atoms` object, read from a LAMMPS dump, a POSCAR, a CIF, an XYZ, built with `ase.build.bulk`, or constructed by hand, can be passed directly to a pyscal function. Results are written back as `atoms.arrays["pyscal_*"]` for per-atom quantities and `atoms.info["pyscal_*"]` for global ones, so they travel with the atoms object and remain accessible to the rest of the ASE ecosystem.

- **Functional API.** Every descriptor is a top-level function in `pyscal` that takes an `Atoms` object as its first argument. Neighbor lists are computed once with `pyscal.find_neighbors(atoms, ...)` and reused by every subsequent descriptor. There is no system state to keep in sync, no method-chaining order to remember, and no class to subclass when adding a new descriptor.

- **Neighbor search on matscipy-neighbours.** The neighbor search uses the C++ core of [matscipy-neighbours](https://github.com/libAtoms/matscipy-neighbours), which is included in pyscal. The neighbors are stored as flat arrays, which the descriptors read directly. For one million atoms with 12 neighbors each, the search takes 0.12 s instead of 28 s in pyscal 3.3.

- **Threads.** The neighbor search, common neighbor analysis and the per-atom loops of the descriptors run on all CPU cores. The results are the same for any number of threads. `pyscal.set_num_threads(n)` or the environment variable `PYSCAL_NUM_THREADS` sets the number of threads.

The C++ core keeps voro++ for tessellation and its own kernels for Steinhardt-type invariants and common neighbor analysis, with pybind11 bindings, and is now exposed through a much thinner Python layer.

A typical session looks like:

```python
import pyscal
from ase.build import bulk

atoms = bulk("Cu", "fcc", cubic=True).repeat(4)
pyscal.find_neighbors(atoms, method="cutoff", cutoff=0)   # adaptive
q4, q6 = pyscal.steinhardt_parameter(atoms, l=[4, 6])
labels, names = pyscal.identify_ackland_jones(atoms)

print(atoms.arrays["pyscal_q6"].mean())   # ≈ 0.57 for fcc
```

### Timings

![Wall time of a neighbor search, adaptive CNA and q6 for one million atoms in pyscal 3.3, pyscal 4, OVITO and freud](https://raw.githubusercontent.com/pyscal/pyscal3/main/docs/_static/benchmark/benchmark.png)

pyscal is as fast as or faster than OVITO and freud.

Scripts written for pyscal 3 need small changes, described in [Migrating from pyscal 3](https://pyscal.org/docs/guide/migration.html). To keep the old interface, install `pyscal3<4`.

## What is included

This release consolidates a number of new descriptors alongside the existing ones:

- Neighbors: fixed cutoff, adaptive cutoff, SANN, a fixed number of neighbors, Voronoi
- Steinhardt $q_l$ and averaged $\bar{q}_l$
- Wigner $W_l$: third-order rotational invariants for distinguishing cubic structures
- Minkowski structure metrics: Voronoi-area-weighted, parameter-free $q_l$
- Solid/liquid classification and clustering
- Disorder parameter
- Angular and $\chi$ parameters, Ackland-Jones structural classifier
- Coordination measures: coordination number, effective coordination, generalised coordination, local density
- Angular distribution function and bond-length distribution function
- Voronoi tessellation: structural vector and Voronoi volume
- Centrosymmetry parameter
- Common neighbor analysis (CNA, adaptive CNA, diamond variants)
- Entropy parameter (Piaggi–Parrinello)
- Warren–Cowley short-range order
- Atomic deformation: strain tensor, von Mises invariant, $D^2_{\min}$, slip vector
- Wigner–Seitz defect analysis: vacancies, interstitials, antisites against a reference
- Atomic Cluster Expansion (ACE) descriptors up to body order four

A complete list with mathematical definitions and examples is available in the [documentation](https://pyscal.org/).

## Installation

pyscal is distributed on PyPI and conda-forge as `pyscal3` (the name `pyscal` on PyPI refers to a separate, unrelated package). After installation, both `import pyscal` and `import pyscal3` work.

From conda-forge:

```
conda install -c conda-forge pyscal3
```

or from PyPI:

```
pip install pyscal3
```

To build from source:

```
git clone https://github.com/pyscal/pyscal3.git
cd pyscal3
pip install .
```

A C++ compiler with C++17 support is required when building from source.

## Third-party code

pyscal3 includes two C++ libraries in `lib/`, compiled into its extension module:

- [voro++](https://math.lbl.gov/voro++/) by Chris H. Rycroft, for Voronoi tessellation.
- [matscipy-neighbours](https://github.com/libAtoms/matscipy-neighbours) by the libAtoms developers, for the neighbour search. MIT licence, see `lib/matscipy-neighbours/LICENSE.md` and `VENDORED.md` in the same directory.

## Citing the work

If you use pyscal in your work, please cite the [following article](https://joss.theoj.org/papers/10.21105/joss.01824):

Sarath Menon, Grisell Díaz Leines and Jutta Rogal (2019). pyscal: A python module for structural analysis of atomic environments. *Journal of Open Source Software* 4(43), 1824. https://doi.org/10.21105/joss.01824

## Works using pyscal

For a list of publications that used pyscal, see [here](https://scholar.google.com/scholar?oi=bibs&hl=en&cites=315020929885190486&as_sdt=5).

## Contributing

Bug reports, questions and contributions are welcome. See [Contributing](https://pyscal.org/docs/contributing.html).
