crystod.phonon

Contents

crystod.phonon#

Phonon analyses of CrystOD: the crystod-phonon command as a library.

This domain covers what crystod-phonon does from phonopy force data (a unit cell with FORCE_SETS or FORCE_CONSTANTS, or a phonopy_params.yaml): labeling phonon modes with ISO-IR space-group irreps, following imaginary modes to the isotropy subgroups they can condense into, exporting eigenvectors for VESTA, resolving the longitudinal/transverse character of bands, and freezing modes into modulated structures. The symmetry-only vibration bases need no force data at all. Where the command takes files, the functions take a live phonopy.Phonopy object; build it with primitive_matrix="auto", so that a zone-boundary instability appears at its own q point instead of being folded onto the supercell Gamma point.

Irrep labeling (crystod-phonon --irreps):

Mode labeling and isotropy subgroups (crystod-phonon --subgroup; the structure-search API):

Eigenvectors and VESTA export (crystod-phonon --vector):

Longitudinal/transverse character (crystod-phonon --lt):

  • get_longitudinal_ratio() – the longitudinal character of every (q point, band) pair: 1 = longitudinal, 0 = transverse.

Modulated structures (crystod-phonon --modulation):

  • SymmetryAdaptedModulation – the symmetry-adapted modes at one q point and the structures obtained by freezing them in (harmonic eigen-displacements on phonopy’s primitive cell as it is; the amplitude is the displacement norm of one primitive cell where 2q is a reciprocal lattice vector);

  • ModulationTerm – the modes and amplitudes of one q point in a combined modulation.

Symmetry-only vibration bases (crystod-phonon --vibration):

Attributes resolve lazily (PEP 562): importing this module is instant and pulls in phonopy/spgrep only on first use. The implementation lives in crystod.phonon_irreps, crystod.phonon_subgroups, crystod.phonon_vector, crystod.phonon_lt, crystod.modulation and crystod.vibration_modes, whose import paths keep working. Bad input raises ValueError from the functions of this namespace, where the implementation modules exit the process (SystemExit) as a command line wants it.

Example:

import phonopy
from crystod import phonon
from crystod.examples import example_path

ph = phonopy.load(
    unitcell_filename=example_path("221_PPOSCAR_SrTiO3"),
    force_sets_filename=example_path("FORCE_SETS_SrTiO3"),
    supercell_matrix=[4, 4, 4], primitive_matrix="auto")

modes = phonon.label_phonon_modes(ph, [0.5, 0.5, 0.5])   # R point
results = phonon.imaginary_mode_subgroups(ph, [0.5, 0.5, 0.5])
for result in results:
    print(result.mode)                                    # R5- soft mode
    for sub in result.subgroups:
        print("   ", sub.label, "->", sub.symbol)         # I4/mcm, R-3c, ...
class crystod.phonon.ImaginaryModeResult(mode, space_group, space_group_number, subgroups, errors=<factory>)[source]#

Bases: object

Isotropy subgroups reachable from one imaginary phonon level.

One block of the crystod-phonon --subgroup report, as returned by imaginary_mode_subgroups() and scan_imaginary_modes().

Variables:
  • mode (crystod.phonon_subgroups.PhononMode) – The imaginary level, a PhononMode.

  • space_group (str) – International short symbol of the parent space group.

  • space_group_number (int) – Its number.

  • subgroups (tuple[crystod.phonon_subgroups.IsotropySubgroup, ...]) – The IsotropySubgroup records of every irrep label of the level, in table order; empty when no label has tabulated subgroups.

  • errors (dict) – Maps an irrep label to the reason its subgroup enumeration failed (e.g. the label of a symmetry line or plane, which has no isotropy subgroups in the tables; "?" when the level carries no label at all). Empty on success.

errors: dict#
mode: PhononMode#
space_group: str#
space_group_number: int#
subgroups: tuple[IsotropySubgroup, ...]#
class crystod.phonon.ModulationTerm(qpoint, mode_indices, amplitudes)[source]#

Bases: object

One modulation term: modes of one q point with their amplitudes.

crystod-phonon --modulation builds one term from --qpoint, --mode and --amplitude, or one per numbered set (--qpoint1, --mode1, --amplitude1, --qpoint2, …); a combined structure sums the terms on their common supercell.

Variables:
  • qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

  • mode_indices (list[int]) – 0-based indices into the mode table of SymmetryAdaptedModulation at that q (the printed table is 1-based).

  • amplitudes (list[float]) – Amplitude in Angstroms of each mode, same length as mode_indices: the norm of the mode’s displacement of one primitive cell at a time-reversal-invariant q (see SymmetryAdaptedModulation.get_modulated_structure()).

amplitudes: list[float]#
mode_indices: list[int]#
qpoint: list[float]#
class crystod.phonon.PhononMode(band_indices, frequency, labels, qpoint, qpoint_label, representative_q)[source]#

Bases: object

One degenerate phonon level at a q point.

Returned by label_phonon_modes(); crystod-phonon --subgroup prints one such level per imaginary mode. str(mode) gives the one-line form "modes 1,2,3: -1.0867 THz  R5-".

Variables:
  • band_indices (tuple[int, ...]) – 1-based band indices of the level (CrystOD convention).

  • frequency (float) – Frequency in THz; negative means imaginary.

  • labels (tuple[str, ...]) – ISO-IR irrep label(s) of the level, without the dimension suffix that phonon_irreps.yaml appends ("R4+", not "R4+(3)"); empty when the level could not be labeled.

  • qpoint (tuple[float, float, float]) – The q point that was asked for, in fractional coordinates of the primitive reciprocal basis.

  • qpoint_label (str | None) – Tabulated name of its star (e.g. "R"), or None for a q point outside every tabulated star.

  • representative_q (tuple[float, float, float]) – The tabulated arm of the star at which the labels were read (equal to qpoint when that is the tabulated arm).

band_indices: tuple[int, ...]#
property degeneracy: int#

Number of bands in the level.

frequency: float#
property is_imaginary: bool#

True when the frequency is negative (no threshold applied).

labels: tuple[str, ...]#
qpoint: tuple[float, float, float]#
qpoint_label: str | None#
representative_q: tuple[float, float, float]#
class crystod.phonon.SymmetryAdaptedModulation(yaml_path=None, qpoint=None, symprec=1e-05, keep_q_coords=False, phonon=None)[source]#

Bases: object

Symmetry-adapted phonon modes at one q point and their frozen-in structures.

The engine of crystod-phonon --modulation. On construction the dynamical matrix of phonon at qpoint is block-diagonalized in the spgrep irrep-projected basis of phonon.primitive as it is (its atom order, positions, lattice and Cartesian frame; no re-standardization), so that the partners of a degenerate level transform with the irrep matrices instead of coming out as arbitrary combinations – the solver shared with crystod-phonon --vector (crystod.symmetry_adapted_modes.solve_symmetry_adapted_modes()); the result is verified against the plain phonopy spectrum. get_modulated_structure() then freezes selected modes into the smallest commensurate supercell of that same cell, and analyze_symmetry() reports the space group of the result.

The frozen-in displacements are true harmonic eigen-displacements (phonopy’s eigenvector divided by the square root of the atomic mass, as phonopy’s own modulation does). At a time-reversal-invariant q (2q a reciprocal lattice vector) every mode vector is real, the partners of a degenerate level are orthonormal real patterns along directions that symmetry operations fix up to sign, chosen and ordered by the isotropy subgroups they freeze into (independent of the origin, orientation and lattice basis of the input; which of several equivalent domains comes first, and the signs, are conventions – the signs of the partners of one level relative to each other do not depend on the origin either, the overall sign at q != 0 only picks one of two copies translated by a lattice vector, and nothing ties the signs of different q points), and the amplitude is the norm of the displacement of one primitive cell. At any other q the vector is a complex Bloch wave whose global phase (a shift of the modulation along the lattice) is fixed by a convention only, not controlled physically, and a single partner of a degenerate level freezes into a structure that depends on that phase.

Parameters:
  • yaml_path (str | None) – A phonopy_params.yaml (.xz accepted) to load the phonopy object from; ignored when phonon is given.

  • qpoint (list[float] | None) – Fractional coordinates of q in the reciprocal basis of phonon.primitive (required).

  • symprec (float) – Symmetry tolerance of the spglib/spgrep analysis.

  • keep_q_coords (bool) – Name a non-special q by its coordinates (q_<coords>) in get_q_label() instead of its ISO-IR k-vector type.

  • phonon – A prebuilt phonopy.Phonopy object with force constants, e.g. from phonopy.load of a unit cell with FORCE_SETS; lets one set of force data drive several q points without reloading it. Build it with primitive_matrix="auto": its primitive cell must be primitive.

Variables:
  • qpoint – The q point as a float array of shape (3,).

  • phonon – The phonopy object.

  • vibrations – The symmetry analysis of phonon.primitive (vibrations.primitive_cell – the cell the structures are built on –, vibrations.rotations, vibrations.translations).

  • irreps – The spgrep irreps of the little group of q.

  • vibration_basis – The irrep-projected basis of the vibration space, one (dim, 3 * n_atoms) array per projected space (rows are kets in phonopy’s phase convention).

  • n_atoms – Number of atoms in the primitive cell.

  • mode_info – One {"frequency_THz": ..., "degeneracy": ...} dict per mode, sorted by frequency (mode i is band i of the phonopy spectrum).

  • mode_vectors – The corresponding freezing vectors, 3 * n_atoms complex components each, v_j = e_j exp(2 pi i q . x_j) / sqrt(m_j) normalized over the primitive cell (e the phonopy eigenvector, x_j the scaled position of atom j in vibrations.primitive_cell); the displacement of atom j in the cell at lattice translation R is amplitude * Re(v_j * exp(2 pi i q . R)). Real at a time-reversal-invariant q.

  • eigenvectors – The same modes as unit eigenvectors of phonopy’s dynamical matrix, in phonopy’s convention (mass-weighted, atom-position phase).

Raises:
  • ValueError – If qpoint is missing, neither yaml_path nor phonon is given, the phonopy object carries no force constants, or its primitive cell is not primitive (crystod.symmetry_adapted_modes.NonPrimitiveCellError).

  • RuntimeError – If the symmetry-adapted construction does not reproduce the phonopy spectrum.

Example

Freeze one component of the R-point soft mode of cubic SrTiO3 (ph as in crystod.phonon.label_phonon_modes()):

from crystod import phonon

modulation = phonon.SymmetryAdaptedModulation(
    phonon=ph, qpoint=[0.5, 0.5, 0.5])
modulation.print_mode_info()            # 15 modes, R5-(3) first
atoms = modulation.get_modulated_structure([0], [0.3])
modulation.analyze_symmetry(atoms)      # I4/mcm (No. 140)
static analyze_symmetry(atoms, symprec=0.1)[source]#

Space group of a structure, printed and returned.

crystod-phonon --modulation reports the space group of the generated structure with this; the default 0.1 is the tolerance the command uses for that report (--tolerance overrides it).

Parameters:
  • atoms (Atoms) – The structure as an ase.Atoms object.

  • symprec (float) – spglib symmetry tolerance.

Returns:

Dict with "international" (short symbol), "number" and "hall" (Hall symbol).

Return type:

dict[str, str | int]

static get_commensurate_supercell_sizes(qpoint)[source]#

Supercell multiplicities along a, b, c commensurate with q.

The smallest diagonal supercell on which the modulation at q is periodic (not always the smallest supercell of all: q = (1/2, 1/2, 0) gives 2 x 2 x 1).

Parameters:

qpoint (list[float] | ndarray[tuple[Any, ...], dtype[float64]]) – Fractional coordinates of q in the primitive reciprocal basis.

Returns:

1 for an integer component, else the denominator of the component.

Return type:

Integer array (n1, n2, n3)

Raises:

ValueError – If a component is not a fraction with a denominator of at most 12 (e.g. 0.15): no such supercell holds the modulation, and freezing it into one would build a structure that is not periodic.

get_mode_labels()[source]#

Per-mode irrep labels, e.g. 'X3-(1)'; '-' when unavailable.

Uses the ISO-IR-table-based labeling of crystod-phonon --vector and --irreps. The label of band i applies to mode i because the symmetry-adapted frequencies are verified to match the plain phonopy spectrum. Computed once and cached.

Returns:

List of n_modes label strings in mode order.

Return type:

list[str]

get_modulated_structure(mode_indices, amplitudes)[source]#

Freeze selected modes into the smallest commensurate supercell.

The supercell is n1 x n2 x n3 copies of vibrations.primitive_cell (phonopy’s primitive cell as it is) with n_i the denominator of the i-th component of q (get_commensurate_supercell_sizes()). Atom j in the cell at lattice translation R is displaced by the sum over the selected modes of amplitude * Re(vector_j * exp(2 pi i q . R)) with vector the mode’s entry of mode_vectors – the harmonic eigen-displacement of the mode; at a time-reversal-invariant q the displacement of every primitive cell has the norm amplitude. The atoms are ordered by species, as a POSCAR wants them.

Parameters:
  • mode_indices (list[int]) – 0-based indices into mode_vectors (the printed mode table is 1-based).

  • amplitudes (list[float]) – Amplitude in Angstroms of each selected mode, same length as mode_indices.

Returns:

The modulated structure as an ase.Atoms object with periodic boundary conditions.

Raises:
  • SystemExit – If a mode index is out of range (the command-line convention; not translated to ValueError for methods).

  • ValueError – If q is not commensurate with a supercell of at most 12 cells per axis.

Return type:

Atoms

get_q_label()[source]#

Short q label for file names.

The ISO-IR name (e.g. 'X') when q lies in the star of a tabulated special point; else the ISO-IR k-vector type of q (e.g. 'DT'); else 'q_<coordinates>', which is also used when keep_q_coords is set. Computed once and cached.

Returns:

The label string.

Return type:

str

print_mode_info()[source]#

Print the mode table: number, frequency (THz), irrep, degeneracy.

Mode numbers are 1-based, as --mode of crystod-phonon --modulation expects them.

eigenvectors: list[ndarray[tuple[Any, ...], dtype[complex128]]]#
mode_info: list[dict[str, float | int]]#
mode_vectors: list[ndarray[tuple[Any, ...], dtype[complex128]]]#
property n_modes: int#

Number of modes at q (3 * n_atoms).

class crystod.phonon.SymmetryOnlyVibrations(cell, symprec=1e-05, standardize=True)[source]#

Bases: _CoreRepresentation

Symmetry-allowed vibration bases of a crystal, without force data.

The engine of crystod-phonon --vibration: at a q point, the displacement representation of the little group of q (the permutation representation of the atoms times the Cartesian rotation, with Bloch phases) is projected onto the spgrep irreps, giving one basis of symmetry-adapted displacement patterns per irrep occurrence. The spaces are labeled with ISO-IR irrep names, and any component can be written out as a displaced structure on the commensurate supercell: the partner of get_symmetry_adapted_spaces() – fixed by the conventions of --modulation, real with the Bloch phase of every atom at a time-reversal-invariant q, so that it freezes into an isotropy subgroup of its irrep – a unit-norm symmetry-adapted displacement pattern, not a normal mode. crystod.symmetry_adapted_modes.solve_symmetry_adapted_modes() (behind crystod-phonon --modulation and --vector) uses the same basis, on phonopy’s primitive cell as it is (standardize=False), to block-diagonalize a dynamical matrix.

Parameters:
  • cell (PhonopyAtoms) – The crystal structure as a phonopy.structure.atoms.PhonopyAtoms object, e.g. from phonopy.interface.calculator.read_crystal_structure.

  • symprec (float) – Symmetry tolerance of the spglib analysis.

  • standardize (bool) – Reduce cell to the spglib primitive cell first (the default; a note is printed). False keeps the input cell as it is, which must then already be primitive; this preserves the caller’s atom positions so that phase conventions stay consistent with an externally built dynamical matrix. Either way the analysis, the Bloch phases and the written supercells all use primitive_cell.

Variables:
  • primitive_cell – The primitive cell the analysis runs on.

  • spglib_dataset – Its spglib symmetry dataset (["number"], ["international"], …).

  • rotations – Rotation parts of the space-group operations in the primitive basis, shape (n_ops, 3, 3).

  • translations – The corresponding translation parts, shape (n_ops, 3).

  • rotations_cartesian – The rotations in Cartesian coordinates.

  • symprec – The symmetry tolerance.

  • labels_from_isoir – True when the last get_irrep_labels() call took its labels from the general ISO-IR k-vector lookup rather than from the special-point table.

Example

List the vibration spaces of cubic ScF3 at the R point:

from phonopy.interface.calculator import read_crystal_structure
from crystod import phonon
from crystod.examples import example_path

cell, _ = read_crystal_structure(
    example_path("221_PPOSCAR_ScF3"), interface_mode="vasp")
vibrations = phonon.SymmetryOnlyVibrations(cell)
label, qpoint = vibrations.resolve_qpoint(["R"])
irreps, spaces, labels = vibrations.describe_mode_spaces(qpoint)
labels                      # ['R1+(1)', 'R3+(2)', 'R4+(3)', ...]
[space.shape for space in spaces]   # [(1, 12), (2, 12), (3, 12), ...]
describe_mode_spaces(qpoint)[source]#

Irreps, projected vibration spaces and their labels at q.

The one-call form of get_vibration_rep(), get_irrep_labels() and get_vibration_basis(), as crystod-phonon --vibration prints them (one “Mode Space” line per irrep occurrence, with its label and dimension).

Parameters:

qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

Returns:

the spgrep irreps, one (dim, 3 * n_atoms) array per irrep occurrence, and the ISO-IR label of each space. The mode-space numbers of the command are 1-based positions in basis_spaces. These are spgrep’s raw projected spaces; the partners the command writes out are those of get_symmetry_adapted_spaces().

Return type:

(irreps, basis_spaces, basis_space_labels)

get_high_symmetry_qpoints()[source]#

High-symmetry q points of the primitive cell, from seekpath.

crystod-phonon --vibration --list-qpoints prints this map. The coordinates are expressed in the reciprocal basis of this object’s (spglib) primitive cell: seekpath’s own primitive cell can differ from it by an integer change of basis (base-centred monoclinic cells, for instance), and the tabulated coordinates are transformed accordingly. A warning is issued only when the two cells are not related by such a change of basis, in which case the coordinates are returned as seekpath gives them.

Returns:

Dict mapping seekpath labels ("GAMMA", "R", "X", …) to fractional coordinates in the primitive reciprocal basis.

Return type:

dict[str, list[float]]

get_irrep_labels(qpoint, irreps, mapping_little_group)[source]#

ISO-IR labels of the spgrep irreps at q.

The characters of each spgrep irrep are matched against the ISO-IR table of the space group: directly at a tabulated special point, by conjugation onto the tabulated arm for another arm of its star, and through the general ISO-IR k-vector lookup (Miller-Love labels) for a symmetry line, plane or generic q. An irrep no table matches keeps its generic irrep_N(dim) label.

Parameters:
  • qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

  • irreps – The spgrep irreps from get_vibration_rep().

  • mapping_little_group (ndarray[tuple[Any, ...], dtype[int64]]) – The little-group indices from get_vibration_rep().

Returns:

One label per irrep, e.g. "R4+(3)" (the irrep name with its dimension).

Return type:

list[str]

get_supercell_displacements(qpoint, mode_vector, supercell_size)[source]#

Displacement pattern of one basis vector on a supercell.

Atom j of the primitive cell at lattice translation R is displaced by Re(mode_j * exp(2 pi i q . (R + x_j))) (unit amplitude), with x_j the scaled position of atom j in primitive_cell, the cell the supercell is built from: the Bloch wave the ket mode describes in the atom-position phase convention. For a row of get_symmetry_adapted_spaces() at a time-reversal-invariant q the displacement of every primitive cell has unit norm.

Parameters:
  • qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

  • mode_vector (ndarray[tuple[Any, ...], dtype[complex128]]) – One row of get_symmetry_adapted_spaces() (what --vibration writes) or of a projected space of describe_mode_spaces() (whose global phase, and at a time-reversal-invariant q its partner basis, spgrep leaves arbitrary), 3 * n_atoms complex components.

  • supercell_size (tuple[int, int, int]) – (n1, n2, n3) multiplicities, e.g. from get_supercell_size().

Returns:

Cartesian positions and displacements of the supercell atoms, shape (n1 * n2 * n3 * n_atoms, 3), their chemical symbols, and the supercell lattice vectors as rows.

Return type:

(positions, displacements, symbols, supercell_lattice)

get_supercell_size(qpoint)[source]#

Supercell multiplicities along a, b, c commensurate with q.

Parameters:

qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

Returns:

1 for a zero component, else the denominator of the component (limited to 6).

Return type:

(n1, n2, n3)

get_symmetry_adapted_spaces(qpoint)[source]#

Symmetry-adapted partners of every mode space, as --vibration freezes them.

The spaces of describe_mode_spaces() (same order, same dimensions) with their partners fixed by the conventions of crystod-phonon --modulation (crystod.symmetry_adapted_modes.solve_symmetry_adapted_spaces(), the mode solver with no dynamical matrix): the spaces of a repeated irrep are an orthonormal basis of its isotypic space fixed by the displacements (the atom orbit each lives on, then how the atoms move along the crystal axes, then the products of the displacements of neighbouring atoms), not the copies spgrep’s projection happens to return; at a time-reversal-invariant q (2q a reciprocal lattice vector) every partner is, with the Bloch factor exp(2 pi i q . x_j) of each atom, a real displacement pattern along a direction symmetry operations fix up to sign – a single partner freezes into an isotropy subgroup of its irrep, whatever the origin; at any other q each space is a complex Bloch wave whose global phase is a convention. A complex irrep and its conjugate, which time reversal joins into one real space at such a q, share its real partners: the first half belongs to the irrep whose label sorts first. At a time-reversal-invariant q the k-th space of a given label thus holds the same partners however q is written (q, q + G or -q); the position of a label in the list follows spgrep’s irrep order at the q given and can differ between those spellings. (At any other q the relative phases of the partners of a larger irrep follow the irrep matrices spgrep builds at the q given.) The rows are unit-norm symmetry-adapted displacement patterns, not normal modes: there are no force constants to select a combination of the spaces of a repeated irrep, and no masses.

Parameters:

qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

Returns:

One (dim, 3 * n_atoms) array per mode space, rows in the atom-position phase convention of get_vibration_basis() (the Bloch factor of each atom not included), ready for get_supercell_displacements().

Return type:

list[ndarray[tuple[Any, …], dtype[complex128]]]

get_vibration_basis(irreps, vibration_rep, irrep_labels=None)[source]#

Project the displacement representation onto each irrep.

Parameters:
Returns:

one (dim, 3 * n_atoms) array per occurrence of an irrep in the displacement representation, and the label of each space. The rows are the symmetry-adapted displacement patterns as kets: for one array B and the irrep matrices d, vibration_rep[g] @ B.T == B.T @ d[g]. They are in the atom-position phase convention of phonopy’s eigenvectors (Bloch factor exp(2 pi i q . x_j) of each atom not included). Repeated occurrences of one irrep transform with the same matrices but are not orthogonal to each other.

Return type:

(basis_vectors, basis_labels)

get_vibration_rep(kpoint)[source]#

Displacement representation of the little group of q.

Parameters:

kpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

Returns:

the spgrep irreps of the little group of q; the representation matrices of the little-group operations on the 3 * n_atoms displacement space, shape (n_little, 3 * n_atoms, 3 * n_atoms); and the indices of the little-group operations within rotations.

Return type:

(irreps, vibration_rep, mapping_little_group)

resolve_qpoint(raw_qpoint)[source]#

Resolve --qpoint tokens into a label and coordinates.

One token is a seekpath label (GM, G and the Greek capital gamma are accepted for GAMMA); three tokens are coordinates in the primitive reciprocal basis, fractions such as 1/3 allowed. Coordinates are labeled with the special point they coincide with, else with the name of the star arm the space-group rotations map them onto, else with the ISO-IR k-vector type of q, else "custom".

Parameters:

raw_qpoint (list[str]) – The tokens, one label or three coordinate strings.

Returns:

(label, qpoint) with qpoint a list of three floats.

Raises:

ValueError – For an unknown label, or a token count other than one or three.

Return type:

tuple[str, list[float]]

write_displaced_structure(positions, displacements, symbols, supercell_lattice, amplitude, output_path)[source]#

Write positions + amplitude * displacements as a POSCAR.

Parameters:
  • positions (ndarray[tuple[Any, ...], dtype[float64]]) – Cartesian positions from get_supercell_displacements().

  • displacements (ndarray[tuple[Any, ...], dtype[float64]]) – The unit-amplitude displacements from the same call.

  • symbols (list[str]) – Chemical symbols of the atoms.

  • supercell_lattice (ndarray[tuple[Any, ...], dtype[float64]]) – Supercell lattice vectors as rows.

  • amplitude (float) – Displacement amplitude in Angstroms.

  • output_path (str) – Output file path (VASP format, direct coordinates).

crystod.phonon.build_symmetry_adapted_modes(phonon, qpoint, symprec=1e-05)[source]#

Symmetry-adapted eigenvectors of the dynamical matrix at q.

The dynamical matrix is block-diagonalized in the spgrep irrep-projected basis of the primitive cell, so that the partners of a degenerate level transform with the irrep matrices instead of coming out as the arbitrary linear combinations a plain eigensolver returns – the solver shared with crystod-phonon --modulation (crystod.symmetry_adapted_modes.solve_symmetry_adapted_modes()). crystod-phonon --vector exports these vectors as VESTA arrows. The result is verified against the plain phonopy solution: the frequencies must match, every vector must be an eigenvector of the dynamical matrix, and the vectors must be orthonormal. At a time-reversal-invariant q (2q a reciprocal lattice vector) the partners of a degenerate level are real displacement patterns (e_j exp(2 pi i q.x_j) real).

Parameters:
  • phonon – A phonopy.Phonopy object with force constants, built with primitive_matrix="auto"; its primitive cell is used as-is (no standardization), so that the projected basis and the dynamical matrix share one phase convention.

  • qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

  • symprec (float) – Symmetry tolerance of the spglib/spgrep analysis.

Returns:

List of (frequency_THz, mode_vector) sorted by frequency (negative for imaginary modes); mode_vector has 3 * n_atoms complex components in the mass-weighted phonopy convention (atom-position phase), as phonopy’s own eigenvectors.

Raises:
  • ValueError – If the primitive cell of phonon is not primitive (crystod.symmetry_adapted_modes.NonPrimitiveCellError).

  • RuntimeError – If the construction cannot reproduce the phonopy spectrum (the projection does not span the vibration space, or the symmetry analysis does not match the dynamical matrix).

Return type:

list[tuple[float, ndarray[tuple[Any, …], dtype[complex128]]]]

Example

>>> from crystod import phonon
>>> # ph: the SrTiO3 object of the label_phonon_modes example
>>> modes = phonon.build_symmetry_adapted_modes(ph, [0.5, 0.5, 0.5])
>>> [round(frequency, 4) for frequency, _ in modes[:4]]
[-1.0867, -1.0867, -1.0867, 3.9891]
>>> modes[0][1].shape
(15,)
crystod.phonon.commensurate_qpoints(phonon)[source]#

q points of the primitive cell commensurate with the phonon supercell.

These are exactly the q points a supercell calculation resolves (the ones that fold onto Gamma of the supercell): for a supercell matrix S in the primitive basis, the det(S) distinct vectors m @ inv(S).T modulo reciprocal-lattice translations. crystod-phonon --subgroup without --qpoint scans this set.

Parameters:

phonon – A phonopy.Phonopy object; only its primitive cell and supercell are read.

Returns:

List of (q1, q2, q3) tuples in fractional coordinates of the primitive reciprocal basis, snapped to exact fractions and sorted by length, so that Gamma comes first.

Raises:

ValueError – If the supercell is not an integer multiple of the primitive cell.

Example

>>> from crystod import phonon
>>> qpoints = phonon.commensurate_qpoints(ph)   # ph: 4x4x4 supercell
>>> len(qpoints), qpoints[0], qpoints[1]
(64, (0.0, 0.0, 0.0), (0.0, 0.0, 0.25))
crystod.phonon.find_star_representative(qpoint, rotations, q_names, q_list)[source]#

Map a q point onto the tabulated arm of its star.

The ISO-IR tables list only one representative arm per special point (e.g. only (1/2, 1/2, 0) for the three M arms of Pm-3m), so a direct coordinate lookup fails for the other arms. Some space-group rotation R sends q onto a tabulated point when q @ R equals it modulo reciprocal-lattice translations; the spectra of star arms coincide band by band, so the labels read at the representative apply to the modes at q. This is how crystod-phonon --irreps/--vector and label_phonon_modes() label a non-representative arm.

Parameters:
  • qpoint (list[float] | ndarray[tuple[Any, ...], dtype[float64]]) – Fractional coordinates of q in the primitive reciprocal basis.

  • rotations (ndarray[tuple[Any, ...], dtype[int64]]) – Rotation parts of the space-group operations, shape (n_ops, 3, 3), in the same (primitive) basis as qpoint and the tabulated points.

  • q_names (list[str]) – Labels of the tabulated special points.

  • q_list (list[list[float]]) – Their coordinates, as returned by get_irt_special_points().

Returns:

(label, representative_q) for the first tabulated point some rotation maps q onto, or None when q lies in no tabulated star.

Return type:

tuple[str, list[float]] | None

Example

>>> from crystod import phonon
>>> from crystod.runtime_compat import get_symmetry_dataset
>>> names = ["GM", "R", "X", "M"]
>>> points = [[0, 0, 0], [0.5, 0.5, 0.5], [0, 0.5, 0], [0.5, 0.5, 0]]
>>> # ph: a phonopy.Phonopy object of cubic SrTiO3 (Pm-3m)
>>> rotations = get_symmetry_dataset(ph.primitive_symmetry)["rotations"]
>>> phonon.find_star_representative([0.5, 0, 0], rotations, names, points)
('X', [0, 0.5, 0])
crystod.phonon.get_commensurate_supercell_matrix(qpoint, base_matrix)[source]#

Smallest diagonal multiple of base_matrix commensurate with q.

crystod-phonon --vector draws a mode on the smallest supercell over which its Bloch phase is periodic: each base-cell axis is multiplied by the denominator of the corresponding component of q in the base reciprocal basis (denominators up to 12).

Parameters:
  • qpoint (list[float]) – Fractional coordinates of q in the primitive reciprocal basis.

  • base_matrix (ndarray[tuple[Any, ...], dtype[int64]]) – Rows are the base-cell (primitive or conventional) lattice vectors in the primitive basis: the identity for the primitive cell, or the matrix of get_conventional_matrix for the conventional cell.

Returns:

Integer matrix S whose rows are the supercell lattice vectors in the primitive basis (L_super = S @ L_primitive), satisfying q . S_row in Z for every row.

Return type:

ndarray[tuple[Any, …], dtype[int64]]

Example

>>> import numpy as np
>>> from crystod import phonon
>>> base = np.eye(3, dtype=int)
>>> phonon.get_commensurate_supercell_matrix([0.0, 0.5, 0.0], base)
array([[1, 0, 0],
       [0, 2, 0],
       [0, 0, 1]])
crystod.phonon.get_irrep_labels(q, phonon, irt_table, prim_mat, degeneracy_tolerance)[source]#

Irrep labels, band indices, and frequencies of the phonon modes at q.

The labeling step of crystod-phonon --irreps: phonopy’s character analysis (Phonopy.set_irreps) groups the bands at q into degenerate sets and computes their characters, and each set is matched against the ISO-IR small irreps of q by character overlap (a set is labeled when the overlap exceeds 0.9). A q point outside the special-point table (a symmetry line or plane, a generic q) is decomposed against the full ISO-IR (ISOTROPY) tables instead, with Miller-Love labels. For a non-representative arm of a star, map q onto the tabulated arm with find_star_representative() first; label_phonon_modes() does both steps in one call.

Parameters:
  • q (list[float]) – Fractional coordinates of q in the primitive reciprocal basis, as tabulated (the representative arm of its star).

  • phonon – A phonopy.Phonopy object with force constants, built with primitive_matrix="auto".

  • irt_table – ISO-IR irrep table of the space group (see get_irt_special_points()).

  • prim_mat – Conventional-to-primitive matrix of the centring.

  • degeneracy_tolerance (float) – Frequency tolerance (THz) within which bands count as degenerate; --tolerance of crystod-phonon --irreps (default 1e-3).

Returns:

one entry of labels per degenerate set, each a list of "R4+(3)"-style labels (the irrep name with its dimension) or None when no tabulated irrep matched; band_indices the 0-based band indices of each set; and frequencies the THz frequencies of all bands at q.

Return type:

(labels, band_indices, frequencies)

Raises:

ValueError – If the q point can be labeled from neither table.

Example

>>> from phonopy.structure.cells import get_primitive_matrix_by_centring
>>> from crystod import phonon
>>> from crystod.irreptables_compat import load_irreptables
>>> IrrepTable, _ = load_irreptables()
>>> table = IrrepTable(221, spinor=False)          # ph: cubic SrTiO3
>>> prim_mat = get_primitive_matrix_by_centring("P")
>>> labels, bands, freqs = phonon.get_irrep_labels(
...     [0.5, 0.5, 0.5], ph, table, prim_mat, 1e-3)
>>> labels[0], bands[0], round(float(freqs[0]), 4)
(['R5-(3)'], [0, 1, 2], -1.0867)
crystod.phonon.get_irt_special_points(irt_table, prim_mat)[source]#

Unique special q points of the ISO-IR tables, in the primitive basis.

The ISO-IR tables list their irreps per special k point in the conventional reciprocal basis; this collects the distinct points, converts them to the primitive basis of the phonopy object, and returns them in table order. crystod-phonon --irreps surveys exactly these points. Coordinates are snapped to exact fractions (1/3 stays 1/3, not 0.333333): decimal-rounded values break the little-group detection and the ISO-IR table lookups downstream.

Parameters:
  • irt_table – ISO-IR irrep table of the space group, i.e. IrrepTable(number, spinor=False) with IrrepTable from crystod.irreptables_compat.load_irreptables().

  • prim_mat – Conventional-to-primitive matrix of the centring, e.g. phonopy.structure.cells.get_primitive_matrix_by_centring("P").

Returns:

the k-point labels ("GM", "R", …) and their fractional coordinates in the primitive reciprocal basis, in the order of the tables (Gamma first).

Return type:

(q_names, q_list)

Example

>>> from phonopy.structure.cells import get_primitive_matrix_by_centring
>>> from crystod import phonon
>>> from crystod.irreptables_compat import load_irreptables
>>> IrrepTable, _ = load_irreptables()
>>> table = IrrepTable(221, spinor=False)          # Pm-3m
>>> prim_mat = get_primitive_matrix_by_centring("P")
>>> names, points = phonon.get_irt_special_points(table, prim_mat)
>>> names
['GM', 'R', 'X', 'M']
>>> points[1]
[0.5, 0.5, 0.5]
crystod.phonon.get_longitudinal_ratio(qpoints, eigenvectors, reciprocal_lattice)[source]#

Longitudinal character of every (q point, band) pair.

The character is sqrt(sum over atoms of |q_hat . e_atom|^2), with q_hat the unit propagation vector and e_atom the three components of the normalized eigenvector on that atom: 1 for a purely longitudinal mode, 0 for a purely transverse one. At the Gamma point no propagation direction exists and the neutral value 0.5 is returned. crystod-phonon --lt colors each band of the band structure by this quantity (red = longitudinal, blue = transverse).

Parameters:
  • qpoints (ndarray[tuple[Any, ...], dtype[float64]]) – Fractional q coordinates along the path, shape (n_q, 3).

  • eigenvectors (ndarray[tuple[Any, ...], dtype[complex128]]) – Eigenvectors of the dynamical matrix, shape (n_q, 3 * n_atoms, n_bands) with the bands in columns, as phonopy returns them (run_qpoints(..., with_eigenvectors=True) or a band structure computed with eigenvectors).

  • reciprocal_lattice (ndarray[tuple[Any, ...], dtype[float64]]) – Reciprocal lattice vectors as rows, used only for the direction of q (with or without the 2 pi factor).

Returns:

Array of shape (n_q, n_bands) with the longitudinal character in [0, 1].

Return type:

ndarray[tuple[Any, …], dtype[float64]]

Example

>>> import numpy as np
>>> from crystod import phonon
>>> from crystod.runtime_compat import get_qpoints_result
>>> qpoints = np.array([[0.0, 0.0, 0.0], [0.25, 0.0, 0.0], [0.5, 0.0, 0.0]])
>>> ph.run_qpoints(qpoints, with_eigenvectors=True)   # ph: cubic SrTiO3
>>> eigenvectors = np.array(get_qpoints_result(ph).eigenvectors)
>>> reciprocal = np.linalg.inv(np.array(ph.primitive.cell)).T
>>> ratio = phonon.get_longitudinal_ratio(qpoints, eigenvectors, reciprocal)
>>> ratio.shape                                       # 15 bands
(3, 15)
crystod.phonon.imaginary_mode_subgroups(phonon, qpoint=(0.0, 0.0, 0.0), *, threshold=-0.1, degeneracy_tolerance=0.0001, with_settings=True)[source]#

Isotropy subgroups of every imaginary phonon level at qpoint.

The symmetry-lowering step of a structure search, and the API form of crystod-phonon --subgroup --qpoint: every degenerate level with frequency below threshold is labeled with label_phonon_modes(), and the isotropy subgroups of its irrep are enumerated with isotropy_subgroups(), covering all order-parameter directions, including the ones a single frozen-in modulation would miss. The acoustic modes at Gamma (uniform translations, at zero frequency) are skipped whatever the threshold: freezing them in moves the crystal and lowers no symmetry.

Parameters:
  • phonon – A live phonopy.Phonopy object with force constants, built with primitive_matrix="auto" (see label_phonon_modes()).

  • qpoint – Fractional coordinates of q in the primitive reciprocal basis.

  • threshold (float) – Frequency (THz) below which a level counts as imaginary; the -0.1 default matches the instability criterion of structure-search workflows.

  • degeneracy_tolerance (float) – Frequency tolerance (THz) within which bands count as degenerate.

  • with_settings (bool) – Also compute the conventional basis/origin of every subgroup (see isotropy_subgroups()).

Returns:

List of ImaginaryModeResult, one per imaginary level in band order. A level that could not be labeled, or whose irrep has no tabulated subgroups, yields a result with empty subgroups and the reason in errors; an empty list means no level lies below threshold.

Raises:

RuntimeError – If the q point cannot be labeled at all (from label_phonon_modes()).

Example

>>> from crystod import phonon
>>> # ph: the SrTiO3 object of the label_phonon_modes example
>>> for result in phonon.imaginary_mode_subgroups(ph, [0.5, 0.5, 0.5]):
...     print(result.mode)
...     for sub in result.subgroups:
...         print("   ", sub.label, "->", sub.symbol)
modes 1,2,3: -1.0867 THz  R5-
    R5-(0,0,a) -> I4/mcm
    R5-(a,a,a) -> R-3c
    R5-(0,a,a) -> Imma
    R5-(0,a,b) -> C2/m
    R5-(a,a,b) -> C2/c
    R5-(a,b,c) -> P-1
crystod.phonon.isotropy_subgroups(space_group, irrep, order_parameter=None, *, with_settings=True)[source]#

Isotropy subgroups of a space-group irrep, as data.

Programmatic counterpart of crystod-group --parent: the order-parameter directions of the irrep (or of the coupled order parameter of several irreps) are enumerated with crystod.group.IsotropyAnalyzer, and each direction is returned with the space group it condenses into. No phonopy object is needed; the function is also exported as crystod.group.isotropy_subgroups.

Parameters:
  • space_group (str | int) – International short symbol (e.g. "Pm-3m") or number (e.g. 221) of the parent.

  • irrep (str | list[str]) – ISO-IR irrep label (e.g. "R4+"); a list of labels enumerates the subgroups of the coupled order parameter.

  • order_parameter (list[str] | None) – If given (e.g. ["a", "0", "0"]), resolve only this direction and return a single-element list. Components are plain numbers or parameter names; composite entries of the enumerated table such as "0.282a" are rejected.

  • with_settings (bool) – Also compute the conventional basis/origin of each subgroup in the parent convention (slightly slower; on by default).

Returns:

List of IsotropySubgroup, sorted like the --parent table (free components, index, subgroup number).

Raises:

ValueError – For an unknown space group, an irrep that is not tabulated for it (the labels of symmetry lines and planes, e.g. DT5, have no isotropy subgroups in the tables), or an invalid order parameter.

Example

>>> from crystod import phonon
>>> for sub in phonon.isotropy_subgroups("Pm-3m", "R4+"):
...     print(sub)
R4+(0,0,a) -> I4/mcm (No. 140), size 2, index 6
R4+(a,a,a) -> R-3c (No. 167), size 2, index 8
R4+(0,a,a) -> Imma (No. 74), size 2, index 12
R4+(0,a,b) -> C2/m (No. 12), size 2, index 24
R4+(a,a,b) -> C2/c (No. 15), size 2, index 24
R4+(a,b,c) -> P-1 (No. 2), size 2, index 48
>>> sub = phonon.isotropy_subgroups(221, "R4+", ["0", "0", "a"])[0]
>>> sub.symbol, sub.basis.tolist()
('I4/mcm', [[-1.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 2.0, 0.0]])
crystod.phonon.label_phonon_modes(phonon, qpoint=(0.0, 0.0, 0.0), *, degeneracy_tolerance=0.0001)[source]#

ISO-IR irrep labels of the phonon modes of phonon at qpoint.

The API form of crystod-phonon --irreps for one q point: the ISO-IR table of the space group is loaded, q is mapped onto the tabulated arm of its star with find_star_representative() (the spectra of star arms coincide band by band), and the degenerate levels are labeled with get_irrep_labels(). The levels come back as PhononMode records with 1-based band indices.

Parameters:
  • phonon – A live phonopy.Phonopy object with force constants available (e.g. from phonopy.load), built with primitive_matrix="auto" so that a zone-boundary instability appears at its own q point instead of being folded onto the supercell Gamma point, where it cannot be labeled.

  • qpoint – Fractional coordinates of q in the primitive reciprocal basis; any arm of a star is accepted.

  • degeneracy_tolerance (float) – Frequency tolerance (THz) within which bands count as degenerate.

Returns:

List of PhononMode, one per degenerate level, ordered by band index.

Raises:

RuntimeError – If the space-group tables cannot label this q point at all.

Example

>>> import phonopy
>>> from crystod import phonon
>>> from crystod.examples import example_path
>>> ph = phonopy.load(
...     unitcell_filename=example_path("221_PPOSCAR_SrTiO3"),
...     force_sets_filename=example_path("FORCE_SETS_SrTiO3"),
...     supercell_matrix=[4, 4, 4], primitive_matrix="auto")
>>> for mode in phonon.label_phonon_modes(ph, [0.5, 0.5, 0.5]):
...     print(mode)
modes 1,2,3: -1.0867 THz  R5-
modes 4,5,6: 3.9891 THz  R4-
modes 7,8,9: 11.6887 THz  R5+
modes 10,11,12: 12.6621 THz  R4-
modes 13,14: 14.8133 THz  R3-
modes 15: 23.2302 THz  R2-
crystod.phonon.resolve_qpoint(raw_qpoint, q_names, q_list, rotations=None, isoir_context=None)[source]#

Resolve --qpoint tokens into a label and primitive-basis coordinates.

This is how crystod-phonon --vector and --subgroup read their --qpoint argument: a single token is the label of a tabulated special point (GM, G, GAMMA and the Greek capital gamma all mean Gamma); three tokens are coordinates in the primitive reciprocal basis, fractions such as 1/3 allowed. Coordinates are labeled with the name of the special point they coincide with. With rotations, any arm of a tabulated star is labeled with the star’s name, not only the tabulated arm; with isoir_context, a q point outside every tabulated star is labeled with its ISO-IR k-vector type (e.g. U, B, DT) instead of q_<coords>.

Parameters:
  • raw_qpoint (list[str]) – The tokens, one label or three coordinate strings.

  • q_names (list[str]) – Labels of the tabulated special points.

  • q_list (list[list[float]]) – Their coordinates, as returned by crystod.phonon.get_irt_special_points().

  • rotations (ndarray[tuple[Any, ...], dtype[int64]] | None) – Space-group rotations in the primitive basis, shape (n_ops, 3, 3), or None to label exact matches only.

  • isoir_context (tuple | None) – (space-group number, primitive cell tuple, symprec) for the ISO-IR fallback label, or None for q_<coords>.

Returns:

(label, qpoint) with qpoint a list of three floats. The coordinates are the ones that were given (not the tabulated arm), so the label names the star while the modes are computed at the requested q.

Raises:

ValueError – For an unknown label, or a token count other than one or three.

Return type:

tuple[str, list[float]]

Example

>>> from crystod import phonon
>>> names = ["GM", "R", "X", "M"]
>>> points = [[0, 0, 0], [0.5, 0.5, 0.5], [0, 0.5, 0], [0.5, 0.5, 0]]
>>> phonon.resolve_qpoint(["R"], names, points)
('R', [0.5, 0.5, 0.5])
>>> # rotations: the primitive-cell rotations of the space group
>>> phonon.resolve_qpoint(["1/2", "0", "0"], names, points, rotations)
('X', [0.5, 0.0, 0.0])
crystod.phonon.scan_imaginary_modes(phonon, qpoints=None, *, threshold=-0.1, degeneracy_tolerance=0.0001, with_settings=True)[source]#

Isotropy subgroups of all imaginary modes at the resolvable q points.

Runs imaginary_mode_subgroups() over qpoints and merges the results; the API form of crystod-phonon --subgroup without --qpoint. Star arms are deduplicated (all arms of a star carry the same levels), and a q point whose modes cannot be labeled is skipped with a warning rather than aborting the scan.

Parameters:
  • phonon – A live phonopy.Phonopy object with force constants, built with primitive_matrix="auto" (see label_phonon_modes()).

  • qpoints – q points to scan, in fractional coordinates of the primitive reciprocal basis; None means commensurate_qpoints() of the phonon supercell.

  • threshold (float) – Frequency (THz) below which a level counts as imaginary.

  • degeneracy_tolerance (float) – Frequency tolerance (THz) within which bands count as degenerate.

  • with_settings (bool) – Also compute the conventional basis/origin of every subgroup (see isotropy_subgroups()).

Returns:

List of ImaginaryModeResult sorted most unstable first (ascending frequency); empty when no level lies below threshold.

Example

>>> from crystod import phonon
>>> results = phonon.scan_imaginary_modes(ph)   # ph: SrTiO3, 4x4x4
>>> [(r.mode.qpoint_label, round(r.mode.frequency, 4)) for r in results]
[('R', -1.0867)]
crystod.phonon.write_vesta_with_arrows(filepath, lattice, scaled_positions, symbols, arrows_cartesian, title, arrow_rgb=(255, 0, 0), arrow_radius=0.5)[source]#

Write a complete VESTA file with per-atom displacement arrows.

The output of crystod-phonon --vector: the structure is written as a P1 cell with one VECTR/VECTT arrow per atom, following the Phonopy_VESTA approach (A. P. Roy et al., Phys. Rev. Lett. 132, 026701 (2024)): a complete file including VESTA’s style sections, since VESTA ignores vectors in files that lack them. Arrow components are written in the VESTA vector convention: values along the a/b/c axis directions with the modulus in Angstroms (equal to Cartesian components for cubic cells).

Parameters:
  • filepath (str) – Output path (.vesta).

  • lattice (ndarray[tuple[Any, ...], dtype[float64]]) – Lattice vectors as rows, in Angstroms, shape (3, 3).

  • scaled_positions (ndarray[tuple[Any, ...], dtype[float64]]) – Fractional atomic coordinates, shape (n_atoms, 3).

  • symbols (list[str]) – Chemical symbols of the atoms (radius and color are taken from VESTA’s element defaults).

  • arrows_cartesian (ndarray[tuple[Any, ...], dtype[float64]]) – Cartesian arrow vectors in Angstroms, shape (n_atoms, 3).

  • title (str) – The VESTA title line.

  • arrow_rgb (tuple[int, int, int]) – Arrow color as an RGB triple (default red).

  • arrow_radius (float) – Arrow radius in VESTA units.

Returns:

None. The file is written to filepath.

Return type:

None

Example

Draw the first R-point mode of SrTiO3 on its 2x2x2 supercell (ph as in crystod.phonon.label_phonon_modes()):

import numpy as np
from crystod import phonon
from crystod.phonon_vector import get_supercell_displacement_field

q = [0.5, 0.5, 0.5]
modes = phonon.build_symmetry_adapted_modes(ph, q)
supercell_matrix = phonon.get_commensurate_supercell_matrix(
    q, np.eye(3, dtype=int))
supercell, field = get_supercell_displacement_field(
    ph, q, supercell_matrix, modes[0][1])
arrows = field.real * (1.5 / np.linalg.norm(field.real, axis=1).max())
phonon.write_vesta_with_arrows(
    "SrTiO3_R_mode1.vesta", np.array(supercell.cell),
    np.array(supercell.scaled_positions), list(supercell.symbols),
    arrows, title="SrTiO3 R mode 1")
class crystod.phonon.IsotropySubgroup[source]#

Alias of crystod.group.IsotropySubgroup, the record type of the subgroups of an ImaginaryModeResult (the same class object, exported from both namespaces; it is documented once, under crystod.group).