Solid-Liquid Classification and Clustering#
pyscal provides two functions for identifying solid and liquid regions:
find_solids— classifies each atom as solid or liquid based on Steinhardt parameters, optionally clustering solid atoms and returning the largest cluster sizefind_clusters— groups connected atoms into clusters based on a boolean condition
import pyscal
from pyscal.structures import make_crystal
from ase.io import read
import numpy as np
Finding Solid Atoms#
find_solids requires neighbors to be found first. Key parameters:
bonds: minimum number of solid-like connections or fraction (0-1)threshold: dot product threshold for solid-like connections (default: 0.5)cluster: if True (default), also run clustering and return largest cluster size
# Perfect FCC crystal - should be all solid
fcc = make_crystal("fcc", lattice_constant=3.6, repetitions=(4, 4, 4))
pyscal.find_neighbors(fcc, method="cutoff", cutoff=0)
# find_solids returns the largest cluster size when cluster=True (default)
largest = pyscal.find_solids(fcc, bonds=0.5, threshold=0.5)
print(f"Largest solid cluster: {largest} atoms out of {len(fcc)}")
# Per-atom solid/liquid classification is stored
solid = np.array(fcc.arrays.get('pyscal_solid', []))
if len(solid) > 0:
n_solid = np.sum(solid > 0)
print(f"Solid atoms: {n_solid} / {len(fcc)} ({100*n_solid/len(fcc):.0f}%)")
Largest solid cluster: 256 atoms out of 256
Solid atoms: 256 / 256 (100%)
Custom Clustering#
find_clusters groups atoms based on any boolean condition. It requires a condition array.
# Cluster based on the solid classification from find_solids
solid_mask = fcc.arrays.get('pyscal_solid', np.zeros(len(fcc))) > 0
largest_size = pyscal.find_clusters(fcc, condition=solid_mask)
print(f"Largest cluster size: {largest_size}")
# Cluster IDs are stored in atoms.arrays
cluster_ids = fcc.arrays.get('pyscal_cluster', np.array([]))
if len(cluster_ids) > 0:
unique_clusters = np.unique(cluster_ids[cluster_ids >= 0])
print(f"Number of clusters: {len(unique_clusters)}")
Largest cluster size: 256
Number of clusters: 1
Working with a Mixed System#
The real power of solid/liquid classification shows with mixed systems.
# Read a liquid-like configuration
lqd = read("conf.lqd.Al.dump", format="lammps-dump-text")
pyscal.find_neighbors(lqd, method="cutoff", cutoff=0)
largest = pyscal.find_solids(lqd, bonds=0.5, threshold=0.5)
print(f"Largest solid cluster: {largest} atoms out of {len(lqd)}")
Largest solid cluster: 0 atoms out of 500