Common Neighbor Analysis (CNA)#

Common Neighbor Analysis identifies the local crystal structure around each atom. pyscal supports both standard CNA and adaptive CNA.

CNA classifies atoms as:

  • 1 = FCC

  • 2 = HCP

  • 3 = BCC

  • 0 = Other / disordered

import pyscal
from pyscal.structures import make_crystal
from ase.io import read
import numpy as np

Basic CNA#

common_neighbor_analysis finds neighbors internally (adaptive CNA by default), so you don’t need to call find_neighbors first. It returns a dict of counts.

fcc = make_crystal("fcc", lattice_constant=3.6, repetitions=(4, 4, 4))
cna = pyscal.common_neighbor_analysis(fcc)
print(f"CNA result: {cna}")

# Per-atom structure IDs are stored in atoms.arrays["pyscal_structure"]
print(f"Per-atom values (unique): {np.unique(fcc.arrays['pyscal_structure'])}")
CNA result: {'others': 0, 'fcc': 256, 'hcp': 0, 'bcc': 0, 'ico': 0}
Per-atom values (unique): [1]

Comparing Structures#

structures = {
    "FCC": make_crystal("fcc", lattice_constant=3.6, repetitions=(4, 4, 4)),
    "BCC": make_crystal("bcc", lattice_constant=2.87, repetitions=(4, 4, 4)),
    "HCP": make_crystal("hcp", lattice_constant=3.2, repetitions=(4, 4, 4), ca_ratio=1.633),
}

for name, s in structures.items():
    cna = pyscal.common_neighbor_analysis(s)
    print(f"{name}: {cna}")
FCC: {'others': 0, 'fcc': 256, 'hcp': 0, 'bcc': 0, 'ico': 0}
BCC: {'others': 0, 'fcc': 0, 'hcp': 0, 'bcc': 128, 'ico': 0}
HCP: {'others': 0, 'fcc': 0, 'hcp': 256, 'bcc': 0, 'ico': 0}

Reading from File#

atoms = read("conf.fcc.dump", format="lammps-dump-text")
cna = pyscal.common_neighbor_analysis(atoms)
print(f"From file: {cna}")
From file: {'others': 439, 'fcc': 564, 'hcp': 0, 'bcc': 5, 'ico': 0}

Diamond Structure Identification#

diamond_structure identifies diamond cubic and diamond hexagonal structures.

Classification codes:

  • 1 = Cubic diamond

  • 2 = Cubic diamond (1st neighbor)

  • 3 = Hexagonal diamond

  • 4 = Hexagonal diamond (1st neighbor)

  • 0 = Other

dia = make_crystal("diamond", lattice_constant=5.43, repetitions=(3, 3, 3))
result = pyscal.diamond_structure(dia)
print(f"Diamond: {result}")
Diamond: {'others': 0, 'cubic diamond': 216, 'cubic diamond 1NN': 0, 'cubic diamond 2NN': 0, 'hex diamond': 0, 'hex diamond 1NN': 0, 'hex diamond 2NN': 0}