CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-phonopy

Comprehensive Python library for phonon calculations that enables lattice dynamics simulations and vibrational property analysis of crystalline materials.

Pending
Overview
Eval results
Files

structure.mddocs/

Crystal Structure Handling

Handle crystalline structure representations, transformations, and symmetry operations for phonon calculations. Phonopy provides comprehensive tools for managing crystal structures including unit cells, supercells, primitive cells, and symmetry operations.

Capabilities

PhonopyAtoms Class

Core container for atomic structure information with comprehensive manipulation capabilities.

class PhonopyAtoms:
    def __init__(
        self,
        symbols: Optional[Sequence] = None,
        numbers: Optional[Union[Sequence, np.ndarray]] = None,
        masses: Optional[Union[Sequence, np.ndarray]] = None,
        magnetic_moments: Optional[Union[Sequence, np.ndarray]] = None,
        scaled_positions: Optional[Union[Sequence, np.ndarray]] = None,
        positions: Optional[Union[Sequence, np.ndarray]] = None,
        cell: Optional[Union[Sequence, np.ndarray]] = None,
        atoms: Optional["PhonopyAtoms"] = None,
        magmoms: Optional[Union[Sequence, np.ndarray]] = None,
        pbc: Optional[bool] = None
    ):
        """
        Initialize atomic structure container.
        
        Parameters:
        - symbols: Chemical symbols as list of strings
        - numbers: Atomic numbers as list/array of integers
        - masses: Atomic masses in atomic mass units (amu)
        - magnetic_moments: Magnetic moments for each atom
        - scaled_positions: Atomic positions in fractional coordinates
        - positions: Atomic positions in Cartesian coordinates (Å)
        - cell: Unit cell lattice vectors as 3x3 array (Å)
        - atoms: Copy from existing PhonopyAtoms object (deprecated)
        - magmoms: Magnetic moments for each atom (deprecated, use magnetic_moments)
        - pbc: Periodic boundary conditions (deprecated, unused)
        """

    def copy(self) -> PhonopyAtoms:
        """Create deep copy of PhonopyAtoms object."""

    def __len__(self) -> int:
        """Get number of atoms in structure."""

    def __getitem__(self, index) -> PhonopyAtoms:
        """Get subset of atoms by index or slice."""

Example:

from phonopy.structure.atoms import PhonopyAtoms
import numpy as np

# Create structure from scratch
lattice = [[4.0, 0.0, 0.0],
           [0.0, 4.0, 0.0], 
           [0.0, 0.0, 4.0]]
           
positions = [[0.0, 0.0, 0.0],
             [0.5, 0.5, 0.5]]
             
symbols = ['Si', 'Si']

atoms = PhonopyAtoms(symbols=symbols,
                     scaled_positions=positions,
                     cell=lattice)

# Alternative using atomic numbers
numbers = [14, 14]  # Silicon
atoms = PhonopyAtoms(numbers=numbers,
                     scaled_positions=positions,
                     cell=lattice)

# Create copy and modify
atoms_copy = atoms.copy()
print(f"Number of atoms: {len(atoms)}")

Structure Properties

Access and manipulate structural properties.

def get_cell(self) -> ndarray:
    """
    Get unit cell lattice vectors.
    
    Returns:
    3x3 array of lattice vectors in Å
    """

def get_positions(self) -> ndarray:
    """
    Get atomic positions in Cartesian coordinates.
    
    Returns:
    Nx3 array of positions in Å
    """

def get_scaled_positions(self) -> ndarray:
    """
    Get atomic positions in fractional coordinates.
    
    Returns:
    Nx3 array of fractional positions [0,1)
    """

def get_masses(self) -> ndarray:
    """
    Get atomic masses.
    
    Returns:
    Array of masses in atomic mass units (amu)
    """

def get_chemical_symbols(self) -> list:
    """
    Get chemical symbols.
    
    Returns:
    List of element symbols as strings
    """

def get_atomic_numbers(self) -> ndarray:
    """
    Get atomic numbers.
    
    Returns:
    Array of atomic numbers (integers)
    """

def get_magnetic_moments(self) -> ndarray:
    """Get magnetic moments for each atom."""

def get_number_of_atoms(self) -> int:
    """Get total number of atoms."""

@property
def volume(self) -> float:
    """Get unit cell volume in ų."""

Example:

# Access structure properties
cell = atoms.get_cell()
positions = atoms.get_positions()  # Cartesian coordinates
scaled_pos = atoms.get_scaled_positions()  # Fractional coordinates
symbols = atoms.get_chemical_symbols()
masses = atoms.get_masses()

print(f"Cell volume: {atoms.volume:.2f} ų")
print(f"Lattice parameters: {np.linalg.norm(cell, axis=1)}")
print(f"Chemical formula: {symbols}")

Structure Modifications

Modify atomic structures for phonon calculations.

def set_cell(self, cell: ArrayLike):
    """
    Set unit cell lattice vectors.
    
    Parameters:
    - cell: 3x3 array of lattice vectors in Å
    """

def set_positions(self, positions: ArrayLike):
    """
    Set atomic positions in Cartesian coordinates.
    
    Parameters:
    - positions: Nx3 array of positions in Å
    """

def set_scaled_positions(self, scaled_positions: ArrayLike):
    """
    Set atomic positions in fractional coordinates.
    
    Parameters:
    - scaled_positions: Nx3 array of fractional positions
    """

def set_masses(self, masses: ArrayLike):
    """
    Set atomic masses.
    
    Parameters:
    - masses: Array of masses in amu
    """

def set_chemical_symbols(self, symbols: list):
    """
    Set chemical symbols.
    
    Parameters:
    - symbols: List of element symbols
    """

def set_magnetic_moments(self, magmoms: ArrayLike):
    """
    Set magnetic moments.
    
    Parameters:
    - magmoms: Array of magnetic moments
    """

Example:

# Scale unit cell (e.g., for thermal expansion)
new_cell = atoms.get_cell() * 1.02  # 2% expansion
atoms.set_cell(new_cell)

# Modify atomic positions
positions = atoms.get_positions()
positions[0] += [0.1, 0.0, 0.0]  # Displace first atom
atoms.set_positions(positions)

# Set custom masses (e.g., for isotope effects)
masses = atoms.get_masses()
masses[0] = 28.0  # Set first atom to Si-28
atoms.set_masses(masses)

Supercell Generation

Create supercells for phonon calculations.

def get_supercell(
    unitcell: PhonopyAtoms,
    supercell_matrix: ArrayLike,
    symprec: float = 1e-5
) -> Supercell:
    """
    Create supercell from unit cell.
    
    Parameters:
    - unitcell: Unit cell PhonopyAtoms object
    - supercell_matrix: 3x3 transformation matrix or [nx, ny, nz]
    - symprec: Symmetry precision for atom mapping
    
    Returns:
    Supercell object (extends PhonopyAtoms)
    """

class Supercell(PhonopyAtoms):
    """Supercell structure class with additional supercell-specific methods."""
    
    def get_supercell_to_unitcell_map(self) -> ndarray:
        """
        Get mapping from supercell atoms to unit cell atoms.
        
        Returns:
        Array mapping each supercell atom to its unit cell origin
        """
    
    def get_unitcell_to_supercell_map(self) -> list:
        """
        Get mapping from unit cell atoms to supercell atoms.
        
        Returns:
        List of arrays containing supercell indices for each unit cell atom
        """

Example:

from phonopy.structure.cells import get_supercell

# Create 2x2x2 supercell
supercell_matrix = [[2, 0, 0], [0, 2, 0], [0, 0, 2]]
supercell = get_supercell(atoms, supercell_matrix)

print(f"Unit cell atoms: {len(atoms)}")
print(f"Supercell atoms: {len(supercell)}")
print(f"Supercell volume: {supercell.volume:.2f} ų")

# Get atom mappings
sc_to_uc_map = supercell.get_supercell_to_unitcell_map()
uc_to_sc_map = supercell.get_unitcell_to_supercell_map()

print(f"Supercell atom 0 maps to unit cell atom: {sc_to_uc_map[0]}")
print(f"Unit cell atom 0 maps to supercell atoms: {uc_to_sc_map[0]}")

Primitive Cell Operations

Handle primitive cell transformations and standardization.

def get_primitive(
    unitcell: PhonopyAtoms,
    primitive_matrix: ArrayLike | str,
    symprec: float = 1e-5
) -> Primitive:
    """
    Create primitive cell from unit cell.
    
    Parameters:
    - unitcell: Unit cell PhonopyAtoms object  
    - primitive_matrix: 3x3 transformation matrix or string ('auto', 'F', 'I', etc.)
    - symprec: Symmetry precision
    
    Returns:
    Primitive cell object (extends PhonopyAtoms)
    """

def get_primitive_matrix(
    spacegroup_type: str,
    lattice: ArrayLike = None
) -> ndarray:
    """
    Get primitive transformation matrix for given space group.
    
    Parameters:
    - spacegroup_type: Bravais lattice type ('P', 'F', 'I', 'A', 'C', 'R')  
    - lattice: Unit cell lattice vectors for rhombohedral case
    
    Returns:
    3x3 primitive transformation matrix
    """

def guess_primitive_matrix(
    unitcell: PhonopyAtoms,
    symprec: float = 1e-5
) -> ndarray:
    """
    Automatically determine primitive matrix from unit cell symmetry.
    
    Parameters:
    - unitcell: Unit cell structure
    - symprec: Symmetry precision
    
    Returns:
    3x3 primitive transformation matrix
    """

class Primitive(PhonopyAtoms):
    """Primitive cell structure class."""
    
    def get_primitive_to_unitcell_map(self) -> ndarray:
        """Get mapping from primitive to unit cell atoms."""
    
    def get_unitcell_to_primitive_map(self) -> list:
        """Get mapping from unit cell to primitive atoms."""

Example:

from phonopy.structure.cells import (get_primitive, get_primitive_matrix, 
                                    guess_primitive_matrix)

# Get primitive cell automatically
primitive = get_primitive(atoms, primitive_matrix='auto')
print(f"Unit cell atoms: {len(atoms)}")
print(f"Primitive cell atoms: {len(primitive)}")

# Get primitive matrix for face-centered cubic
fcc_matrix = get_primitive_matrix('F')
print("FCC primitive matrix:")
print(fcc_matrix)

# Guess primitive matrix from symmetry
guessed_matrix = guess_primitive_matrix(atoms, symprec=1e-5)
print("Guessed primitive matrix:")
print(guessed_matrix)

# Apply specific primitive matrix
primitive_custom = get_primitive(atoms, fcc_matrix)

Crystal Symmetry

Analyze and apply crystal symmetry operations.

class Symmetry:
    """Crystal symmetry operations and analysis."""
    
    def __init__(
        self,
        cell: PhonopyAtoms,
        symprec: float = 1e-5,
        angle_tolerance: float = -1.0,
        is_symmetry: bool = True
    ):
        """
        Initialize symmetry analysis.
        
        Parameters:
        - cell: Crystal structure  
        - symprec: Symmetry precision
        - angle_tolerance: Angle tolerance for symmetry detection
        - is_symmetry: Whether to use symmetry
        """
    
    def get_symmetry_operations(self) -> dict:
        """
        Get symmetry operations.
        
        Returns:
        Dictionary with 'rotations' and 'translations' arrays
        """
    
    def get_reciprocal_operations(self) -> ndarray:
        """Get symmetry operations in reciprocal space."""
    
    def get_pointgroup_operations(self) -> ndarray:
        """Get point group operations (rotations only)."""
    
    def get_international_table(self) -> str:
        """Get international space group symbol."""
    
    def get_wyckoff_positions(self) -> list:
        """Get Wyckoff positions for atoms."""
    
    @property
    def dataset(self) -> dict:
        """Symmetry dataset from spglib."""

Example:

from phonopy.structure.symmetry import Symmetry

# Analyze crystal symmetry
symmetry = Symmetry(atoms, symprec=1e-5)

# Get symmetry operations
sym_ops = symmetry.get_symmetry_operations()
rotations = sym_ops['rotations']
translations = sym_ops['translations']

print(f"Number of symmetry operations: {len(rotations)}")
print(f"Space group: {symmetry.get_international_table()}")

# Get point group operations
point_group = symmetry.get_pointgroup_operations()
print(f"Point group order: {len(point_group)}")

# Wyckoff positions
wyckoff = symmetry.get_wyckoff_positions()
print(f"Wyckoff positions: {wyckoff}")

Brillouin Zone Operations

Handle Brillouin zone operations and k-point generation.

class BrillouinZone:
    """Brillouin zone operations and k-point handling."""
    
    def __init__(
        self,
        primitive: PhonopyAtoms,
        mesh: ArrayLike = None,
        is_shift: ArrayLike = None,
        is_time_reversal: bool = True,
        is_gamma_center: bool = False,
        rotations: ArrayLike = None,
        qpoints: ArrayLike = None
    ):
        """
        Initialize Brillouin zone operations.
        
        Parameters:
        - primitive: Primitive cell structure
        - mesh: k-point mesh dimensions [nx, ny, nz]
        - is_shift: Mesh shift [sx, sy, sz]
        - is_time_reversal: Apply time-reversal symmetry
        - is_gamma_center: Center mesh on gamma point
        - rotations: Symmetry rotation matrices
        - qpoints: Specific q-points to use
        """
    
    def get_qpoints(self) -> ndarray:
        """Get q-points in reciprocal space."""
    
    def get_weights(self) -> ndarray:
        """Get integration weights for q-points."""
    
    def get_grid_points(self) -> ndarray:
        """Get grid point indices."""
    
    def get_ir_reciprocal_mesh(self) -> tuple:
        """
        Get irreducible reciprocal mesh.
        
        Returns:
        Tuple of (grid_points, weights, grid_mapping)
        """

Distance Calculations

Calculate atomic distances and coordination environments.

class ShortestPairs:
    """Calculate shortest interatomic distances and coordination."""
    
    def __init__(
        self,
        cell: PhonopyAtoms,
        cutoff_radius: float = None
    ):
        """
        Initialize distance calculations.
        
        Parameters:
        - cell: Crystal structure
        - cutoff_radius: Maximum distance to consider (Å)
        """
    
    def get_shortest_distances(self) -> ndarray:
        """Get shortest distances between atoms."""
    
    def get_nearest_neighbors(self, atom_index: int) -> dict:
        """
        Get nearest neighbors for specific atom.
        
        Parameters:
        - atom_index: Index of target atom
        
        Returns:
        Dictionary with neighbor indices, distances, and vectors
        """

Structure Creation Examples

From Crystallographic Data

# Silicon diamond structure
lattice_parameter = 5.43  # Å
lattice = [[lattice_parameter, 0, 0],
           [0, lattice_parameter, 0],
           [0, 0, lattice_parameter]]

positions = [[0.0, 0.0, 0.0],
             [0.25, 0.25, 0.25]]

si_structure = PhonopyAtoms(
    symbols=['Si', 'Si'],
    scaled_positions=positions,
    cell=lattice
)

# Face-centered cubic (FCC) structure
fcc_lattice = [[0.0, 2.0, 2.0],
               [2.0, 0.0, 2.0],
               [2.0, 2.0, 0.0]]

fcc_structure = PhonopyAtoms(
    symbols=['Al'],
    scaled_positions=[[0.0, 0.0, 0.0]],
    cell=fcc_lattice
)

From File Formats

from phonopy.interface.vasp import read_vasp
from phonopy.interface.phonopy_yaml import PhonopyYaml

# Read from VASP POSCAR
atoms_vasp = read_vasp("POSCAR")

# Read from phonopy.yaml
ph_yaml = PhonopyYaml("phonopy.yaml")
atoms_yaml = ph_yaml.unitcell

Structure Transformations

# Apply strain to unit cell
strain_matrix = [[1.02, 0, 0],      # 2% expansion along a
                 [0, 1.0, 0],       # No change along b  
                 [0, 0, 0.98]]      # 2% compression along c

strained_cell = np.dot(atoms.get_cell(), strain_matrix)
atoms_strained = atoms.copy()
atoms_strained.set_cell(strained_cell)

# Rotate structure
from scipy.spatial.transform import Rotation
rotation = Rotation.from_euler('z', 45, degrees=True)  # 45° around z
rotation_matrix = rotation.as_matrix()

rotated_cell = np.dot(atoms.get_cell(), rotation_matrix.T)
rotated_positions = np.dot(atoms.get_positions(), rotation_matrix.T)

atoms_rotated = atoms.copy()
atoms_rotated.set_cell(rotated_cell)
atoms_rotated.set_positions(rotated_positions)

Complete Structure Workflow

from phonopy import Phonopy
from phonopy.structure.atoms import PhonopyAtoms
from phonopy.structure.cells import get_supercell, get_primitive
from phonopy.structure.symmetry import Symmetry

# 1. Create or load unit cell structure
unitcell = PhonopyAtoms(
    symbols=['Mg', 'O'],
    scaled_positions=[[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]],
    cell=[[4.2, 0, 0], [0, 4.2, 0], [0, 0, 4.2]]
)

# 2. Analyze symmetry
symmetry = Symmetry(unitcell, symprec=1e-5)
print(f"Space group: {symmetry.get_international_table()}")

# 3. Get primitive cell
primitive = get_primitive(unitcell, primitive_matrix='auto')
print(f"Primitive cell volume: {primitive.volume:.2f} ų")

# 4. Create supercell for phonon calculations
supercell_matrix = [[2, 0, 0], [0, 2, 0], [0, 0, 2]]
supercell = get_supercell(unitcell, supercell_matrix)

# 5. Initialize Phonopy with structures
ph = Phonopy(unitcell, supercell_matrix, primitive_matrix='auto')

print(f"Unit cell: {len(ph.unitcell)} atoms")
print(f"Primitive: {len(ph.primitive)} atoms") 
print(f"Supercell: {len(ph.supercell)} atoms")

Install with Tessl CLI

npx tessl i tessl/pypi-phonopy

docs

cli-tools.md

core-phonopy.md

gruneisen.md

index.md

loading.md

qha.md

structure.md

tile.json