All public functions are available directly from importpyscal (or, equivalently, importpyscal3).
Results are stored on the ASE Atoms object with the pyscal_ prefix.
Calculate the third-order Steinhardt invariant W_l.
W_l is the third-order rotational invariant of the bond-orientational
order parameters, constructed by contracting q_lm with Wigner 3j
symbols. It distinguishes crystal structures that have similar q_l
values (e.g., FCC vs HCP via the sign of W_6).
Parameters:
atoms (ase.Atoms) – Structure with neighbors already computed via find_neighbors.
l (int or list of int) – Order(s) for the W parameter. Only even values give nonzero
results (W_l = 0 for odd l when j1=j2=j3=l).
These are Voronoi face-area weighted Steinhardt parameters
(Mickel et al., J. Chem. Phys. 138, 044501, 2013). For each atom
i and angular-momentum order l the metric is
where A_j is the Voronoi face area between atoms i and j, and
α is the exponent voroexp.
This function performs Voronoi neighbor finding internally, so there is
no need to call find_neighbors() beforehand (any existing neighbor
data is overwritten).
Parameters:
atoms (ase.Atoms) – The atomic structure (periodic boundary conditions recommended).
l (int or list of int) – Steinhardt parameter order(s), e.g. 6 or [4, 6].
One array per requested l, each of shape (natoms,).
Values are also stored in atoms.arrays["pyscal_q{l}"]
(or "pyscal_avg_q{l}" when averaged=True).
Return type:
list of numpy arrays
Notes
Unlike a plain steinhardt_parameter call after Voronoi neighbor
finding, this function guarantees that Voronoi neighbors are
(re)computed with the requested voroexp so results are
reproducible regardless of prior state.
References
W. Mickel, S. C. Kapfer, G. E. Schröder-Turk and K. Mecke,
“Shortcomings of the bond orientational order parameters for the
analysis of disordered particulate matter”,
J. Chem. Phys.138, 044501 (2013).
doi:10.1063/1.4774084
Classify atomic environments with the Ackland–Jones method.
Uses the chi-parameter histogram (angular signature) to assign each
atom a structure type via a decision tree. The chi histogram bins
cosines of all pairwise neighbor angles into 9 ranges; the counts in
specific bins discriminate FCC, HCP, BCC, and icosahedral (ICO)
environments.
The algorithm follows Ackland & Jones, Phys. Rev. B73, 054104
(2006), adapted for the 9-bin chi scheme used by pyscal3.
:param atoms: pyscal3.find_neighbors()).
:type atoms: ase.Atoms Structure with neighbors already computed (via
Returns:
labels (numpy.ndarray of int, shape (natoms,)) – Per-atom structure label:
Value
Structure
0
other / unknown
1
FCC
2
HCP
3
BCC
4
ICO (icosahedral)
names (list of str) – Human-readable name for each atom ("fcc", "hcp", etc.).
Also stored in atoms.arrays["pyscal_structure"].
Notes
Chi-parameter bin edges (9 bins, cosine of the angle):
Bin
Cosine range
χ₀
[−1.000, −0.945) ~180°
χ₁
[−0.945, −0.915) ~160°
χ₂
[−0.915, −0.755) ~139°
χ₃
[−0.755, −0.705) ~135°
χ₄
[−0.705, −0.195)
χ₅
[−0.195, +0.195) ~90°
χ₆
[+0.195, +0.245)
χ₇
[+0.245, +0.795) ~60°
χ₈
[+0.795, +1.000] ~0°
Decision tree (ideal counts for perfect structures):
G. J. Ackland and A. P. Jones, “Applications of local crystal
structure measures in experiment and simulation”,
Phys. Rev. B73, 054104 (2006).
doi:10.1103/PhysRevB.73.054104
where \(N_{\max}\) is the maximum (bulk) coordination number.
Parameters:
atoms (ase.Atoms) – Structure with neighbors already computed.
cn_max (int or None) – Bulk coordination number. If None, uses the maximum CN observed
in the system.
Returns:
Per-atom GCN values. Also stored in
atoms.arrays["pyscal_gcn"].
Return type:
numpy.ndarray, shape (natoms,)
References
F. Calle-Vallejo et al., “Finding optimal surface sites on
heterogeneous catalysts by counting nearest neighbors”,
Science350, 185 (2015).
doi:10.1126/science.aab3501
Calculate the angular distribution function (ADF).
The ADF is the histogram of all bond angles \(\theta_{jik}\) formed
by pairs of neighbors (j, k) around each atom i. It characterises the
local angular environment independently of a specific order parameter.
Parameters:
atoms (ase.Atoms) – Structure with neighbors already computed.
bins (int) – Number of histogram bins in the angle range [0, 180] degrees.
Default 180 (1-degree resolution).
Returns:
(adf, angles) – adf is the normalised probability density of bond angles, and
angles is the array of bin left-edges in degrees.
Return type:
tuple of numpy.ndarray
Notes
Angles are computed from the cosine of the angle between displacement
vectors, using the same C++ infrastructure as chi_params().
Results are also stored in atoms.info["pyscal_adf"] and
atoms.info["pyscal_adf_angles"].
Calculate the bond-length distribution function (BLDF).
Unlike the full radial distribution function, the BLDF histograms only
the bonds defined by the current neighbor list (no shell-volume
normalisation).
Parameters:
atoms (ase.Atoms) – Structure with neighbors already computed.
bins (int) – Number of histogram bins. Default 100.
rmin (float or None) – Distance range. If None, determined from the data.
rmax (float or None) – Distance range. If None, determined from the data.
Returns:
(bldf, r) – bldf is the normalised probability density, and r is the
array of bin left-edges. Results are also stored in
atoms.info["pyscal_bldf"] and atoms.info["pyscal_bldf_r"].
Calculate the atomic (Green-Lagrange) strain tensor for each atom.
The local deformation gradient F is computed by minimizing the
squared difference between reference and deformed neighbor vectors.
The Lagrangian strain is then E = (F^T F - I) / 2.
:param atoms:
:type atoms: ase.Atoms Deformed configuration with neighbors computed.
:param reference: Reference (undeformed) configuration with the same neighbor list.
:type reference: ase.Atoms
Returns:
Green-Lagrange strain tensor per atom.
Also stored as atoms.arrays["pyscal_strain"].
Return type:
numpy.ndarray of shape (natoms, 3, 3)
Notes
Both configurations must have neighbors computed with identical
neighbor lists (same method and cutoff).
Reference: Falk & Langer, PRE 57 (1998) 7192 (D^2_min);
Shimizu, Ogata, Li, Mat. Trans. 48 (2007) 2923 (atomic strain).
The slip vector s_i = (1/N_s) sum_j (dX_ij - dx_ij) is the average
difference between reference and current displacement vectors,
without fitting an affine transformation.
Parameters:
atoms (ase.Atoms) – Deformed configuration.
reference (ase.Atoms) – Reference configuration.
Returns:
Slip vector per atom.
Also stored as atoms.arrays["pyscal_slip_vector"].
Return type:
numpy.ndarray of shape (natoms, 3)
Notes
Ref: Zimmerman, Kelchner, Klein, Hamilton, Foiles, PRL 87 (2001) 165507.
Wigner-Seitz cell analysis for vacancy/interstitial detection.
This assigns each atom in atoms to the nearest lattice site in reference
and counts site occupancies. Sites with occupancy 0 are vacancies; sites
with occupancy > 1 contain interstitials.
Parameters:
atoms (Atoms) – The configuration to analyze (containing defects).
reference (Atoms) – The perfect/reference configuration defining lattice sites.
affine_mapping (str, optional) – How to handle cell distortion:
- “none” (default): Use positions as-is
- “to_reference”: Rescale atoms positions to match reference cell
per_type_occupancies (bool, optional) – If True, track occupancy by atom type (for antisite detection).
Returns:
Keys:
- “vacancy_count”: Number of sites with occupancy = 0
- “interstitial_count”: Total excess atoms (sum of max(occ-1, 0))
- “occupancy”: (N_ref,) array of site occupancies
- “site_index”: (N_atoms,) array mapping each atom to its assigned site
- “vacancy_indices”: indices of reference sites with vacancies
- “interstitial_sites”: indices of sites with excess atoms
If per_type_occupancies=True, also includes:
- “occupancy_by_type”: dict mapping type → (N_ref,) occupancy array
Return type:
dict
Notes
Results are also stored on atoms:
- atoms.arrays[“pyscal_ws_site_index”]: site assignment
- atoms.arrays[“pyscal_ws_occupancy”]: occupancy of assigned site
- atoms.info[“pyscal_ws_vacancy_count”]
- atoms.info[“pyscal_ws_interstitial_count”]
The algorithm uses nearest-neighbor search via cKDTree. For periodic
systems, reference sites near cell boundaries are replicated to handle
atoms that may have wrapped to different periodic images.
ACE provides a systematic and complete expansion of atomic environments,
with SOAP (nu=2) and bispectrum (nu=3) as special cases. The descriptors
are rotationally, translationally, and permutationally invariant.
The implementation follows Drautz (2019) and computes B-basis descriptors
by coupling A-functions (single-particle basis) to form rotationally
invariant combinations at each correlation order.
Parameters:
atoms (ase.Atoms) – Structure with neighbors already computed.
nmax (int, default 4) – Number of radial basis functions. Higher values capture finer
radial resolution but increase computation.
lmax (int, default 4) – Maximum angular momentum quantum number. Higher values capture
more angular detail. Typically 3-6 for ML potentials.
nu_max (int, default 2) – Maximum correlation order:
- nu=1: Radial density (neighbor count per shell)
- nu=2: Pair correlations (SOAP power spectrum)
- nu=3: Triplet correlations (bispectrum)
Higher orders rapidly increase descriptor count.
cutoff (float, optional) – Neighbor cutoff radius. If None, uses the cutoff from
find_neighbors.
normalize (bool, default True) – If True, normalize descriptors to unit norm per atom.
Load the data of a block into memory as a dictionary
of numpy arrays
Parameters:
blockno (int) – number of the block to be read, starts from 0
Return type:
None
Notes
When the data of a block is loaded, it is accessible
through Trajectory.data[x]. This data can then be
modified. When the block is written out, the modified
data is written instead of existing one. But, loaded
data is kept in memory until unloaded using unload
method.