# `symphon` API Reference

This document provides a detailed overview of the Python API available in the `symphon` package. The package is divided into three main modules:

1. **Phonon Irreducible Representations** (`irreps_anaddb`): Analyzing phonon modes and assigning irrep labels using outputs from ABINIT/anaddb or directly via Phonopy.
2. **Chiral Phase Transitions** (`chiral_transitions`): Group-theoretical analysis of displacive phase transitions to determine accessible chiral (Sohncke) space groups.
3. **Magnetic Phase Transitions** (`magnetic_transitions`): Finding symmetry-adapted magnetic transitions.

---

## 1. Phonon Irreducible Representations (`irreps_anaddb.py`)

This module provides tools to read phonon frequencies and eigenvectors, compute the symmetry-adapted irreducible representations (irreps), and determine their IR/Raman activity.

### `class IrRepsAnaddb(IrRepsEigen)`
Helper class tied to the ANADDB `PHBST` (phonon band structure) output file.

**Initialization:**
```python
IrRepsAnaddb(
    phbst_fname: str,
    ind_q: int,
    symprec: float = 1e-5,
    degeneracy_tolerance: float = 1e-5,
    log_level: int = 0
)
```
- `phbst_fname`: Path to the netCDF `PHBST` file generated by `anaddb`.
- `ind_q`: Index of the q-point to analyze.
- `symprec`: Symmetry tolerance.
- `degeneracy_tolerance`: Tolerance for identifying degenerate phonon modes.

**Key Methods:**
- `run(kpname=None)`: Performs the irrep calculation and labels the modes.
- `get_summary_table() -> list[dict]`: Returns a structured list of dictionaries with mode properties (frequency in THz and cm⁻¹, irrep label, IR/Raman activity). 

### `class IrRepsPhonopy(IrRepsEigen)`
Helper class for analyzing irreps directly using Phonopy calculated objects.

**Initialization:**
```python
IrRepsPhonopy(
    phonopy_params,
    qpoint,
    symprec: float | None = None,
    degeneracy_tolerance: float = 1e-5,
    log_level: int = 0
)
```
- `phonopy_params`: A Phonopy object containing the force constants/dynamical matrix.
- `qpoint`: A 3-element list/array representing the fractional q-point coordinates.

### Single Q-point Query Methods (`IrRepsEigen`)

Both `IrRepsAnaddb` and `IrRepsPhonopy` inherit from `IrRepsEigen`, which provides extensive query functionalities for the computed modes at the specified q-point:

- `get_spacegroup() -> str`: Get the parent structure space group symbol.
- `get_frequencies(unit: str = "THz")`: Return mode frequencies in specified unit (`"THz"`, `"eV"`, `"meV"`, `"cm-1"`).
- `get_eigenvalues(unit: str = "THz")`: Return mode eigenvalues (signed omega^2) in specified unit.
- `get_eigenvectors()`: Return mode eigenvectors.
- `get_eigendisplacements()`: Return mass-weighted eigendisplacements.
- `is_ir_active(mode_index: int) -> bool`: Check if mode is IR active (Gamma only).
- `is_raman_active(mode_index: int) -> bool`: Check if mode is Raman active (Gamma only).
- `get_bcs_labels() -> list[str | None]`: Get the Bilbao Crystallographic Server labels for all modes.
- `get_mulliken_labels() -> list[str | None]`: Get the Mulliken labels for all modes (Gamma only).
- `get_bcs_label(mode_index: int) -> str | None`: Get the Bilbao Crystallographic Server label for a specific mode.
- `get_mulliken_label(mode_index: int) -> str | None`: Get the Mulliken label for a specific mode (Gamma only).
- `get_ir_indices() -> list[int]`: Return indices of all IR active modes.
- `get_raman_indices() -> list[int]`: Return indices of all Raman active modes.
- `get_indices_by_mulliken(label: str) -> list[int]`: Return mode indices matching a given Mulliken label.
- `get_indices_by_bcs(label: str) -> tuple[np.ndarray, str | None, list[int]]`: Return q-point coordinates, q-point name, and mode indices matching a given BCS label.

### Multi-Q-Point Functions

The following functions iterate over all special q-points:

- `get_special_qpoints(primitive_atoms, symprec=1e-5)`: Returns a list of all special q-points for the structure, including conventions handling. Each item contains `label`, `qpoint_bcs` (standard basis) and `qpoint_input` (current cell basis).
- `get_all_irreps_phonopy(phonopy_params, ...)`: Automatically computes irreps for all special q-points using Phonopy. Returns a dictionary mapping the q-point label to an `IrRepsPhonopy` instance.
- `get_all_irreps_anaddb(phbst_fname, ...)`: Automatically computes irreps for all q-points defined in the PHBST file. Returns a dictionary mapping the q-point index to an `IrRepsAnaddb` instance. 


### Convenience Functions

```python
def print_irreps(
    phbst_fname: str,
    ind_q: int,
    ...
)
```
Quickly prints the calculated irreps directly to the standard output using an ANADDB file.

```python
def print_irreps_phonopy(
    phonopy_params,
    qpoint,
    ...
)
```
Quickly prints the calculated irreps directly to the standard output using a Phonopy object.

---

### Example Usage

Here is a quick example of how to use the single-qpoint and multi-qpoint querying functionalities with the `IrRepsPhonopy` interface:

```python
from symphon.irreps_anaddb import IrRepsPhonopy, get_all_irreps_phonopy

# 1. Single Q-Point Analysis (Gamma point)
qpoint_gamma = [0.0, 0.0, 0.0]
irr_gamma = IrRepsPhonopy("BaTiO3_phonopy_params.yaml", qpoint_gamma)

# Compute the irreps
irr_gamma.run(kpname="GM")

# Access parent space group
print("Spacegroup:", irr_gamma.get_spacegroup())

# Fetch full lists of labels for all modes
mulliken_labels = irr_gamma.get_mulliken_labels()
bcs_labels = irr_gamma.get_bcs_labels()

# Check specific mode properties (e.g., Mode index 0)
print("Mode 0 Mulliken Label:", irr_gamma.get_mulliken_label(0))
print("Mode 0 BCS Label:", irr_gamma.get_bcs_label(0))
print("Is Mode 0 IR Active?", irr_gamma.is_ir_active(0))

# Find modes with a specific label
coords, kpname, indices = irr_gamma.get_indices_by_bcs("GM4-")
print(f"Modes with 'GM4-' at {kpname} ({coords}): {indices}")

# 2. Multi Q-Point Analysis (All special q-points automatically)
print("\n--- Special Q-points ---")
all_irreps = get_all_irreps_phonopy("BaTiO3_phonopy_params.yaml")
for q_label, irr in all_irreps.items():
    print(f"Q-point: {q_label}")
    print(f"  Frequencies (THz): {irr.get_frequencies()[:3]}...") # First 3 modes
    print(f"  Frequencies (cm-1): {irr.get_frequencies('cm-1')[:3]}...")
    print(f"  BCS Labels: {irr.get_bcs_labels()[:3]}...")
```

---

## 2. Chiral Phase Transitions (`chiral_transitions.py`)

This module allows for the discovery of accessible chiral daughter phases by evaluating the isotropy subgroups of structural distortions.

### `class ChiralTransitionFinder`
Main class to find all possible chiral phase transitions from a given parent space group.

**Initialization:**
```python
ChiralTransitionFinder(spg_number: int, symprec: float = 1e-5)
```
- `spg_number`: International space group number (1-230).

**Properties:**
- `spacegroup_info`: Returns a `SpaceGroupInfo` object containing rotations and translations.
- `is_parent_chiral`: Boolean indicating if the parent is already a Sohncke group.
- `is_parent_centrosymmetric`: Boolean indicating if the parent contains an inversion center.

**Key Methods:**
- `get_special_qpoints() -> list[tuple[np.ndarray, str]]`: Returns a list of special q-points from the BCS irrep tables along with their labels.
- `get_irreps_at_qpoint(qpoint: np.ndarray, qpoint_label: str) -> list[dict]`: Gets irrep labels and small representation matrices at a specific q-point.
- `find_chiral_transitions(qpoint=None, qpoint_label=None, irrep_label=None) -> list[ChiralTransition]`: Finds all chiral daughter phases accessible via displacive transitions. If `qpoint` is not specified, it sweeps all special q-points.
- `find_chiral_transitions_simple(...)`: A fallback simplified variant that only searches proper subgroups without full spgrep-modulation enumeration.

### Data Classes and Enums

#### `class ChiralTransition`
Dataclass representing a discovered phase transition.
- `parent_spg_number`, `parent_spg_symbol`
- `qpoint`, `qpoint_label`, `irrep_label`, `irrep_dimension`
- `daughter_spg_number`, `daughter_spg_symbol`, `daughter_spg_order`
- `domain_multiplicity`: Number of structural domains formed.
- `enantiomeric_domain_count`: Number of chiral domains (0, 1, or 2).
- `lost_operations`: List of `LostOperation` objects.
- `lost_inversion`, `lost_mirrors`, `lost_glides`: Summaries of symmetry breaking.
- `sohncke_class`: `SohnckeClass` enum classification.
- `enantiomorph_partner`: Space group number of the opposite hand, if any.

#### `class SpaceGroupInfo`
Dataclass holding standard symmetry information of a space group (symbol, number, rotations, translations).

#### `enum SohnckeClass`
Categorizes space groups by chirality:
- `CLASS_I`: Achiral space group.
- `CLASS_II`: Chiral space group with a distinct enantiomorphous partner (e.g., $P4_1$ and $P4_3$).
- `CLASS_III`: Chiral space group without an enantiomorphous partner.

#### `enum ImproperOperationType`
Categorizes broken symmetries: `INVERSION`, `MIRROR`, `GLIDE`, `ROTOUNVERSION`.

### Utility Functions

- `is_sohncke(spg_number: int) -> bool`: Returns `True` if the space group is one of the 65 Sohncke groups.
- `get_sohncke_numbers() -> list[int]`: Returns a list of all 65 Sohncke space group numbers.
- `get_sohncke_class(spg_number: int) -> SohnckeClass`: Evaluates the chirality class.
- `get_enantiomorph_partner(spg_number: int) -> int | None`: Returns the enantiomorphic partner SG number, or `None`.
- `format_transition_table(transitions: list[ChiralTransition]) -> str`: Returns a formatted string suitable for CLI display or text logs.

---

## 3. Magnetic Phase Transitions (`magnetic_transitions.py`)

Provides capabilities to identify symmetry-breaking magnetic configurations.

### `class MagneticTransitionFinder`

**Initialization:**
```python
MagneticTransitionFinder(
    cell: tuple[np.ndarray, list[list[float]], list[int]], 
    magnetic_sites: list[int], 
    symprec: float = 1e-5
)
```
- `cell`: A standard `spglib` cell tuple `(lattice, positions, numbers)`.
- `magnetic_sites`: Indices of atoms where magnetic moments can reside.
- `symprec`: Symmetry tolerance.

**Key Methods:**
- `find_magnetic_irreps(qpoint: list[float])`: Finds the symmetry-adapted magnetic basis vectors for the given crystal and q-point.
- `build_supercell(qpoint, opd, basis)`: Constructs the supercell lattice and spin configurations corresponding to an order parameter direction.
- `check_chirality(dataset) -> bool`: Analyzes a magnetic symmetry dataset to evaluate chiral features.
- `find_transitions(qpoint: list[float]) -> list[dict]`: Discovers accessible magnetic space groups by applying symmetry-adapted distortions.

### `class AbstractMagneticTransitionFinder` (`abstract_magnetic.py`)

A pure group-theoretical implementation to find possible magnetic space group phase transitions without providing any input crystal structure. It evaluates generic time-odd (magnetic) order parameters transforming according to the abstract space group irreducible representations.

**Initialization:**
```python
AbstractMagneticTransitionFinder(
    spg_number: int, 
    symprec: float = 1e-5
)
```
- `spg_number`: International space group number of the parent paramagnetic phase (1-230). Will raise a `ValueError` if the parent is already a chiral (Sohncke) group.
- `symprec`: Symmetry tolerance.

**Key Methods:**
- `find_transitions(qpoint: list[float], include_multi_k: bool = False) -> list[dict]`: Identifies all magnetic subgroups resulting from the generic time-odd order parameter condensing at the specified `qpoint`. Returns a list of dictionaries detailing the transitions, including the `bns_number` (Magnetic Space Group), `irrep_index`, `opd` (Order Parameter Direction), and whether the transition is purely chiral (`is_chiral`). If `include_multi_k` is True, it will evaluate superpositions of multiple arms of the star of q.
- `format_transition_table(qpoint: list[float], transitions: list[dict]) -> str`: Formats the results into a markdown-compatible table for output logs or CLI displays.
